diff mbox series

[net-next,5/5] selftests: tls: add rekey tests

Message ID 803aee7cbc1321a06795ec194685931d6aeec53d.1673952268.git.sd@queasysnail.net (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series tls: implement key updates for TLS1.3 | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers fail 6 maintainers not CCed: edumazet@google.com linux-kselftest@vger.kernel.org davem@davemloft.net kuba@kernel.org pabeni@redhat.com shuah@kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning CHECK: Please don't use multiple blank lines WARNING: Missing commit description - Add an appropriate one WARNING: line length of 83 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 99 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Sabrina Dubroca Jan. 17, 2023, 1:45 p.m. UTC
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
---
 tools/testing/selftests/net/tls.c | 258 ++++++++++++++++++++++++++++++
 1 file changed, 258 insertions(+)

Comments

Apoorv Kothari Jan. 20, 2023, 6:51 a.m. UTC | #1
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> ---
>  tools/testing/selftests/net/tls.c | 258 ++++++++++++++++++++++++++++++
>  1 file changed, 258 insertions(+)
> 
> diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
> index 5f3adb28fee1..97c20e2246e1 100644
> --- a/tools/testing/selftests/net/tls.c
> +++ b/tools/testing/selftests/net/tls.c
> @@ -1453,6 +1453,264 @@ TEST_F(tls, shutdown_reuse)
>      EXPECT_EQ(errno, EISCONN);
>  }
>  
> +#define TLS_RECORD_TYPE_HANDSHAKE      0x16
> +/* key_update, length 1, update_not_requested */
> +static const char key_update_msg[] = "\x18\x00\x00\x01\x00";
> +static void tls_send_keyupdate(struct __test_metadata *_metadata, int fd)
> +{
> +    size_t len = sizeof(key_update_msg);
> +
> +    EXPECT_EQ(tls_send_cmsg(fd, TLS_RECORD_TYPE_HANDSHAKE,
> +                (char *)key_update_msg, len, 0),
> +          len);
> +}
> +
> +static void tls_recv_keyupdate(struct __test_metadata *_metadata, int fd, int flags)
> +{
> +    char buf[100];
> +
> +    EXPECT_EQ(tls_recv_cmsg(_metadata, fd, TLS_RECORD_TYPE_HANDSHAKE, buf, sizeof(buf), flags),
> +          sizeof(key_update_msg));
> +    EXPECT_EQ(memcmp(buf, key_update_msg, sizeof(key_update_msg)), 0);
> +}
> +
> +/* set the key to 0 then 1 for RX, immediately to 1 for TX */
> +TEST_F(tls_basic, rekey_rx)
> +{
> +    struct tls_crypto_info_keys tls12_0, tls12_1;

nit: Did you mean tls13_0 and tls13_1? There are also a few others in this patch.

> +    char const *test_str = "test_message";
> +    int send_len = strlen(test_str) + 1;
> +    char buf[20];
> +    int ret;
> +
> +    if (self->notls)
> +        return;
> +
> +    tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
> +                 &tls12_0, 0);
> +    tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
> +                 &tls12_1, 1);
> +
> +
> +    ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
> +    ASSERT_EQ(ret, 0);
> +
> +    ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_0, tls12_0.len);
> +    ASSERT_EQ(ret, 0);
> +
> +    ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
> +    EXPECT_EQ(ret, 0);
> +
> +    EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
> +    EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
> +}
> +
> +/* set the key to 0 then 1 for TX, immediately to 1 for RX */
> +TEST_F(tls_basic, rekey_tx)
> +{
> +    struct tls_crypto_info_keys tls12_0, tls12_1;
> +    char const *test_str = "test_message";
> +    int send_len = strlen(test_str) + 1;
> +    char buf[20];
> +    int ret;
> +
> +    if (self->notls)
> +        return;
> +
> +    tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
> +                 &tls12_0, 0);
> +    tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
> +                 &tls12_1, 1);
> +
> +
> +    ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_0, tls12_0.len);
> +    ASSERT_EQ(ret, 0);
> +
> +    ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
> +    ASSERT_EQ(ret, 0);
> +
> +    ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
> +    EXPECT_EQ(ret, 0);
> +
> +    EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
> +    EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
> +}
> +
> +TEST_F(tls, rekey)
> +{
> +    char const *test_str_1 = "test_message_before_rekey";
> +    char const *test_str_2 = "test_message_after_rekey";
> +    struct tls_crypto_info_keys tls12;
> +    int send_len;
> +    char buf[100];
> +
> +    if (variant->tls_version != TLS_1_3_VERSION)
> +        return;
> +
> +    /* initial send/recv */
> +    send_len = strlen(test_str_1) + 1;
> +    EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
> +    EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
> +
> +    /* update TX key */
> +    tls_send_keyupdate(_metadata, self->fd);
> +    tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
> +    EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
> +
> +    /* send after rekey */
> +    send_len = strlen(test_str_2) + 1;
> +    EXPECT_EQ(send(self->fd, test_str_2, send_len, 0), send_len);
> +
> +    /* can't receive the KeyUpdate without a control message */
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
> +
> +    /* get KeyUpdate */
> +    tls_recv_keyupdate(_metadata, self->cfd, 0);
> +
> +    /* recv blocking -> -EKEYEXPIRED */
> +    EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), 0), -1);
> +    EXPECT_EQ(errno, EKEYEXPIRED);
> +
> +    /* recv non-blocking -> -EKEYEXPIRED */
> +    EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
> +    EXPECT_EQ(errno, EKEYEXPIRED);
> +
> +    /* update RX key */
> +    EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
> +
> +    /* recv after rekey */
> +    EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
> +    EXPECT_EQ(memcmp(buf, test_str_2, send_len), 0);
> +}
> +
> +TEST_F(tls, rekey_peek)
> +{
> +    char const *test_str_1 = "test_message_before_rekey";
> +    struct tls_crypto_info_keys tls12;
> +    int send_len;
> +    char buf[100];
> +
> +    if (variant->tls_version != TLS_1_3_VERSION)
> +        return;
> +
> +    send_len = strlen(test_str_1) + 1;
> +    EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
> +
> +    /* update TX key */
> +    tls_send_keyupdate(_metadata, self->fd);
> +    tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
> +    EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
> +
> +    EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
> +    EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
> +
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
> +    EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
> +
> +    /* can't receive the KeyUpdate without a control message */
> +    EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
> +
> +    /* peek KeyUpdate */
> +    tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
> +
> +    /* get KeyUpdate */
> +    tls_recv_keyupdate(_metadata, self->cfd, 0);
> +
> +    /* update RX key */
> +    EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
> +}
> +
> +TEST_F(tls, splice_rekey)
> +{
> +    int send_len = TLS_PAYLOAD_MAX_LEN / 2;
> +    char mem_send[TLS_PAYLOAD_MAX_LEN];
> +    char mem_recv[TLS_PAYLOAD_MAX_LEN];
> +    struct tls_crypto_info_keys tls12;
> +    int p[2];
> +
> +    if (variant->tls_version != TLS_1_3_VERSION)
> +        return;
> +
> +    memrnd(mem_send, sizeof(mem_send));
> +
> +    ASSERT_GE(pipe(p), 0);
> +    EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
> +
> +    /* update TX key */
> +    tls_send_keyupdate(_metadata, self->fd);
> +    tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
> +    EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
> +
> +    EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
> +
> +    EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
> +    EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
> +    EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
> +
> +    /* can't splice the KeyUpdate */
> +    EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
> +    EXPECT_EQ(errno, EINVAL);
> +
> +    /* peek KeyUpdate */
> +    tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
> +
> +    /* get KeyUpdate */
> +    tls_recv_keyupdate(_metadata, self->cfd, 0);
> +
> +    /* can't splice before updating the key */
> +    EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
> +    EXPECT_EQ(errno, EKEYEXPIRED);
> +
> +    /* update RX key */
> +    EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
> +
> +    EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
> +    EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
> +    EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
> +}
> +
> +TEST_F(tls, rekey_getsockopt)
> +{
> +    struct tls_crypto_info_keys tls12;
> +    struct tls_crypto_info_keys tls12_get;
> +    socklen_t len;
> +
> +    tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 0);
> +
> +    len = tls12.len;
> +    EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
> +    EXPECT_EQ(len, tls12.len);
> +    EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
> +
> +    len = tls12.len;
> +    EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
> +    EXPECT_EQ(len, tls12.len);
> +    EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
> +
> +    if (variant->tls_version != TLS_1_3_VERSION)
> +        return;
> +
> +    tls_send_keyupdate(_metadata, self->fd);
> +    tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
> +    EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
> +
> +    tls_recv_keyupdate(_metadata, self->cfd, 0);
> +    EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
> +
> +    len = tls12.len;
> +    EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
> +    EXPECT_EQ(len, tls12.len);
> +    EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
> +
> +    len = tls12.len;
> +    EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
> +    EXPECT_EQ(len, tls12.len);
> +    EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
> +}
> +
>  FIXTURE(tls_err)
>  {
>      int fd, cfd;
> -- 
> 2.38.1
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 5f3adb28fee1..97c20e2246e1 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -1453,6 +1453,264 @@  TEST_F(tls, shutdown_reuse)
 	EXPECT_EQ(errno, EISCONN);
 }
 
+#define TLS_RECORD_TYPE_HANDSHAKE      0x16
+/* key_update, length 1, update_not_requested */
+static const char key_update_msg[] = "\x18\x00\x00\x01\x00";
+static void tls_send_keyupdate(struct __test_metadata *_metadata, int fd)
+{
+	size_t len = sizeof(key_update_msg);
+
+	EXPECT_EQ(tls_send_cmsg(fd, TLS_RECORD_TYPE_HANDSHAKE,
+				(char *)key_update_msg, len, 0),
+		  len);
+}
+
+static void tls_recv_keyupdate(struct __test_metadata *_metadata, int fd, int flags)
+{
+	char buf[100];
+
+	EXPECT_EQ(tls_recv_cmsg(_metadata, fd, TLS_RECORD_TYPE_HANDSHAKE, buf, sizeof(buf), flags),
+		  sizeof(key_update_msg));
+	EXPECT_EQ(memcmp(buf, key_update_msg, sizeof(key_update_msg)), 0);
+}
+
+/* set the key to 0 then 1 for RX, immediately to 1 for TX */
+TEST_F(tls_basic, rekey_rx)
+{
+	struct tls_crypto_info_keys tls12_0, tls12_1;
+	char const *test_str = "test_message";
+	int send_len = strlen(test_str) + 1;
+	char buf[20];
+	int ret;
+
+	if (self->notls)
+		return;
+
+	tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+			     &tls12_0, 0);
+	tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+			     &tls12_1, 1);
+
+
+	ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
+	ASSERT_EQ(ret, 0);
+
+	ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_0, tls12_0.len);
+	ASSERT_EQ(ret, 0);
+
+	ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
+	EXPECT_EQ(ret, 0);
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+/* set the key to 0 then 1 for TX, immediately to 1 for RX */
+TEST_F(tls_basic, rekey_tx)
+{
+	struct tls_crypto_info_keys tls12_0, tls12_1;
+	char const *test_str = "test_message";
+	int send_len = strlen(test_str) + 1;
+	char buf[20];
+	int ret;
+
+	if (self->notls)
+		return;
+
+	tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+			     &tls12_0, 0);
+	tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+			     &tls12_1, 1);
+
+
+	ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_0, tls12_0.len);
+	ASSERT_EQ(ret, 0);
+
+	ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
+	ASSERT_EQ(ret, 0);
+
+	ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
+	EXPECT_EQ(ret, 0);
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_F(tls, rekey)
+{
+	char const *test_str_1 = "test_message_before_rekey";
+	char const *test_str_2 = "test_message_after_rekey";
+	struct tls_crypto_info_keys tls12;
+	int send_len;
+	char buf[100];
+
+	if (variant->tls_version != TLS_1_3_VERSION)
+		return;
+
+	/* initial send/recv */
+	send_len = strlen(test_str_1) + 1;
+	EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+	/* update TX key */
+	tls_send_keyupdate(_metadata, self->fd);
+	tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+	EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+	/* send after rekey */
+	send_len = strlen(test_str_2) + 1;
+	EXPECT_EQ(send(self->fd, test_str_2, send_len, 0), send_len);
+
+	/* can't receive the KeyUpdate without a control message */
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
+
+	/* get KeyUpdate */
+	tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+	/* recv blocking -> -EKEYEXPIRED */
+	EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), 0), -1);
+	EXPECT_EQ(errno, EKEYEXPIRED);
+
+	/* recv non-blocking -> -EKEYEXPIRED */
+	EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
+	EXPECT_EQ(errno, EKEYEXPIRED);
+
+	/* update RX key */
+	EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+	/* recv after rekey */
+	EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+	EXPECT_EQ(memcmp(buf, test_str_2, send_len), 0);
+}
+
+TEST_F(tls, rekey_peek)
+{
+	char const *test_str_1 = "test_message_before_rekey";
+	struct tls_crypto_info_keys tls12;
+	int send_len;
+	char buf[100];
+
+	if (variant->tls_version != TLS_1_3_VERSION)
+		return;
+
+	send_len = strlen(test_str_1) + 1;
+	EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+
+	/* update TX key */
+	tls_send_keyupdate(_metadata, self->fd);
+	tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+	EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+	EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
+	EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+	/* can't receive the KeyUpdate without a control message */
+	EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
+
+	/* peek KeyUpdate */
+	tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
+
+	/* get KeyUpdate */
+	tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+	/* update RX key */
+	EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+}
+
+TEST_F(tls, splice_rekey)
+{
+	int send_len = TLS_PAYLOAD_MAX_LEN / 2;
+	char mem_send[TLS_PAYLOAD_MAX_LEN];
+	char mem_recv[TLS_PAYLOAD_MAX_LEN];
+	struct tls_crypto_info_keys tls12;
+	int p[2];
+
+	if (variant->tls_version != TLS_1_3_VERSION)
+		return;
+
+	memrnd(mem_send, sizeof(mem_send));
+
+	ASSERT_GE(pipe(p), 0);
+	EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
+
+	/* update TX key */
+	tls_send_keyupdate(_metadata, self->fd);
+	tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+	EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+	EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
+
+	EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
+	EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+
+	/* can't splice the KeyUpdate */
+	EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
+	EXPECT_EQ(errno, EINVAL);
+
+	/* peek KeyUpdate */
+	tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
+
+	/* get KeyUpdate */
+	tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+	/* can't splice before updating the key */
+	EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
+	EXPECT_EQ(errno, EKEYEXPIRED);
+
+	/* update RX key */
+	EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+	EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
+	EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, rekey_getsockopt)
+{
+	struct tls_crypto_info_keys tls12;
+	struct tls_crypto_info_keys tls12_get;
+	socklen_t len;
+
+	tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 0);
+
+	len = tls12.len;
+	EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
+	EXPECT_EQ(len, tls12.len);
+	EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+	len = tls12.len;
+	EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
+	EXPECT_EQ(len, tls12.len);
+	EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+	if (variant->tls_version != TLS_1_3_VERSION)
+		return;
+
+	tls_send_keyupdate(_metadata, self->fd);
+	tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+	EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+	tls_recv_keyupdate(_metadata, self->cfd, 0);
+	EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+	len = tls12.len;
+	EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
+	EXPECT_EQ(len, tls12.len);
+	EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+	len = tls12.len;
+	EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
+	EXPECT_EQ(len, tls12.len);
+	EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+}
+
 FIXTURE(tls_err)
 {
 	int fd, cfd;