Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  tls.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

#define _GNU_SOURCE

#include <arpa/inet.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <linux/tls.h>
#include <linux/tcp.h>
#include <linux/socket.h>

#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/stat.h>

#include "../kselftest_harness.h"

#define TLS_PAYLOAD_MAX_LEN 16384
#define SOL_TLS 282

static int fips_enabled;

struct tls_crypto_info_keys {
 union {
  struct tls_crypto_info crypto_info;
  struct tls12_crypto_info_aes_gcm_128 aes128;
  struct tls12_crypto_info_chacha20_poly1305 chacha20;
  struct tls12_crypto_info_sm4_gcm sm4gcm;
  struct tls12_crypto_info_sm4_ccm sm4ccm;
  struct tls12_crypto_info_aes_ccm_128 aesccm128;
  struct tls12_crypto_info_aes_gcm_256 aesgcm256;
  struct tls12_crypto_info_aria_gcm_128 ariagcm128;
  struct tls12_crypto_info_aria_gcm_256 ariagcm256;
 };
 size_t len;
};

static void tls_crypto_info_init(uint16_t tls_version, uint16_t cipher_type,
     struct tls_crypto_info_keys *tls12,
     char key_generation)
{
 memset(tls12, key_generation, sizeof(*tls12));
 memset(tls12, 0, sizeof(struct tls_crypto_info));

 switch (cipher_type) {
 case TLS_CIPHER_CHACHA20_POLY1305:
  tls12->len = sizeof(struct tls12_crypto_info_chacha20_poly1305);
  tls12->chacha20.info.version = tls_version;
  tls12->chacha20.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_AES_GCM_128:
  tls12->len = sizeof(struct tls12_crypto_info_aes_gcm_128);
  tls12->aes128.info.version = tls_version;
  tls12->aes128.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_SM4_GCM:
  tls12->len = sizeof(struct tls12_crypto_info_sm4_gcm);
  tls12->sm4gcm.info.version = tls_version;
  tls12->sm4gcm.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_SM4_CCM:
  tls12->len = sizeof(struct tls12_crypto_info_sm4_ccm);
  tls12->sm4ccm.info.version = tls_version;
  tls12->sm4ccm.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_AES_CCM_128:
  tls12->len = sizeof(struct tls12_crypto_info_aes_ccm_128);
  tls12->aesccm128.info.version = tls_version;
  tls12->aesccm128.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_AES_GCM_256:
  tls12->len = sizeof(struct tls12_crypto_info_aes_gcm_256);
  tls12->aesgcm256.info.version = tls_version;
  tls12->aesgcm256.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_ARIA_GCM_128:
  tls12->len = sizeof(struct tls12_crypto_info_aria_gcm_128);
  tls12->ariagcm128.info.version = tls_version;
  tls12->ariagcm128.info.cipher_type = cipher_type;
  break;
 case TLS_CIPHER_ARIA_GCM_256:
  tls12->len = sizeof(struct tls12_crypto_info_aria_gcm_256);
  tls12->ariagcm256.info.version = tls_version;
  tls12->ariagcm256.info.cipher_type = cipher_type;
  break;
 default:
  break;
 }
}

static void memrnd(void *s, size_t n)
{
 int *dword = s;
 char *byte;

 for (; n >= 4; n -= 4)
  *dword++ = rand();
 byte = (void *)dword;
 while (n--)
  *byte++ = rand();
}

static void ulp_sock_pair(struct __test_metadata *_metadata,
     int *fd, int *cfd, bool *notls)
{
 struct sockaddr_in addr;
 socklen_t len;
 int sfd, ret;

 *notls = false;
 len = sizeof(addr);

 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 addr.sin_port = 0;

 *fd = socket(AF_INET, SOCK_STREAM, 0);
 sfd = socket(AF_INET, SOCK_STREAM, 0);

 ret = bind(sfd, &addr, sizeof(addr));
 ASSERT_EQ(ret, 0);
 ret = listen(sfd, 10);
 ASSERT_EQ(ret, 0);

 ret = getsockname(sfd, &addr, &len);
 ASSERT_EQ(ret, 0);

 ret = connect(*fd, &addr, sizeof(addr));
 ASSERT_EQ(ret, 0);

 *cfd = accept(sfd, &addr, &len);
 ASSERT_GE(*cfd, 0);

 close(sfd);

 ret = setsockopt(*fd, IPPROTO_TCP, TCP_ULP, "tls"sizeof("tls"));
 if (ret != 0) {
  ASSERT_EQ(errno, ENOENT);
  *notls = true;
  printf("Failure setting TCP_ULP, testing without tls\n");
  return;
 }

 ret = setsockopt(*cfd, IPPROTO_TCP, TCP_ULP, "tls"sizeof("tls"));
 ASSERT_EQ(ret, 0);
}

/* Produce a basic cmsg */
static int tls_send_cmsg(int fd, unsigned char record_type,
    void *data, size_t len, int flags)
{
 char cbuf[CMSG_SPACE(sizeof(char))];
 int cmsg_len = sizeof(char);
 struct cmsghdr *cmsg;
 struct msghdr msg;
 struct iovec vec;

 vec.iov_base = data;
 vec.iov_len = len;
 memset(&msg, 0, sizeof(struct msghdr));
 msg.msg_iov = &vec;
 msg.msg_iovlen = 1;
 msg.msg_control = cbuf;
 msg.msg_controllen = sizeof(cbuf);
 cmsg = CMSG_FIRSTHDR(&msg);
 cmsg->cmsg_level = SOL_TLS;
 /* test sending non-record types. */
 cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
 cmsg->cmsg_len = CMSG_LEN(cmsg_len);
 *CMSG_DATA(cmsg) = record_type;
 msg.msg_controllen = cmsg->cmsg_len;

 return sendmsg(fd, &msg, flags);
}

static int __tls_recv_cmsg(struct __test_metadata *_metadata,
      int fd, unsigned char *ctype,
      void *data, size_t len, int flags)
{
 char cbuf[CMSG_SPACE(sizeof(char))];
 struct cmsghdr *cmsg;
 struct msghdr msg;
 struct iovec vec;
 int n;

 vec.iov_base = data;
 vec.iov_len = len;
 memset(&msg, 0, sizeof(struct msghdr));
 msg.msg_iov = &vec;
 msg.msg_iovlen = 1;
 msg.msg_control = cbuf;
 msg.msg_controllen = sizeof(cbuf);

 n = recvmsg(fd, &msg, flags);

 cmsg = CMSG_FIRSTHDR(&msg);
 EXPECT_NE(cmsg, NULL);
 EXPECT_EQ(cmsg->cmsg_level, SOL_TLS);
 EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE);
 if (ctype)
  *ctype = *((unsigned char *)CMSG_DATA(cmsg));

 return n;
}

static int tls_recv_cmsg(struct __test_metadata *_metadata,
    int fd, unsigned char record_type,
    void *data, size_t len, int flags)
{
 unsigned char ctype;
 int n;

 n = __tls_recv_cmsg(_metadata, fd, &ctype, data, len, flags);
 EXPECT_EQ(ctype, record_type);

 return n;
}

FIXTURE(tls_basic)
{
 int fd, cfd;
 bool notls;
};

FIXTURE_SETUP(tls_basic)
{
 ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
}

FIXTURE_TEARDOWN(tls_basic)
{
 close(self->fd);
 close(self->cfd);
}

/* Send some data through with ULP but no keys */
TEST_F(tls_basic, base_base)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];

 ASSERT_EQ(strlen(test_str) + 1, send_len);

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
};

TEST_F(tls_basic, bad_cipher)
{
 struct tls_crypto_info_keys tls12;

 tls12.crypto_info.version = 200;
 tls12.crypto_info.cipher_type = TLS_CIPHER_AES_GCM_128;
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1);

 tls12.crypto_info.version = TLS_1_2_VERSION;
 tls12.crypto_info.cipher_type = 50;
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1);

 tls12.crypto_info.version = TLS_1_2_VERSION;
 tls12.crypto_info.cipher_type = 59;
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1);

 tls12.crypto_info.version = TLS_1_2_VERSION;
 tls12.crypto_info.cipher_type = 10;
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1);

 tls12.crypto_info.version = TLS_1_2_VERSION;
 tls12.crypto_info.cipher_type = 70;
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, sizeof(struct tls12_crypto_info_aes_gcm_128)), -1);
}

TEST_F(tls_basic, recseq_wrap)
{
 struct tls_crypto_info_keys tls12;
 char const *test_str = "test_read";
 int send_len = 10;

 if (self->notls)
  SKIP(return"no TLS support");

 tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_128, &tls12, 0);
 memset(&tls12.aes128.rec_seq, 0xff, sizeof(tls12.aes128.rec_seq));

 ASSERT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
 ASSERT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), -1);
 EXPECT_EQ(errno, EBADMSG);
}

FIXTURE(tls)
{
 int fd, cfd;
 bool notls;
};

FIXTURE_VARIANT(tls)
{
 uint16_t tls_version;
 uint16_t cipher_type;
 bool nopad, fips_non_compliant;
};

FIXTURE_VARIANT_ADD(tls, 12_aes_gcm)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_AES_GCM_128,
};

FIXTURE_VARIANT_ADD(tls, 13_aes_gcm)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_AES_GCM_128,
};

FIXTURE_VARIANT_ADD(tls, 12_chacha)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
 .fips_non_compliant = true,
};

FIXTURE_VARIANT_ADD(tls, 13_chacha)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
 .fips_non_compliant = true,
};

FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_SM4_GCM,
 .fips_non_compliant = true,
};

FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_SM4_CCM,
 .fips_non_compliant = true,
};

FIXTURE_VARIANT_ADD(tls, 12_aes_ccm)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_AES_CCM_128,
};

FIXTURE_VARIANT_ADD(tls, 13_aes_ccm)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_AES_CCM_128,
};

FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_256)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_AES_GCM_256,
};

FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_AES_GCM_256,
};

FIXTURE_VARIANT_ADD(tls, 13_nopad)
{
 .tls_version = TLS_1_3_VERSION,
 .cipher_type = TLS_CIPHER_AES_GCM_128,
 .nopad = true,
};

FIXTURE_VARIANT_ADD(tls, 12_aria_gcm)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_ARIA_GCM_128,
};

FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256)
{
 .tls_version = TLS_1_2_VERSION,
 .cipher_type = TLS_CIPHER_ARIA_GCM_256,
};

FIXTURE_SETUP(tls)
{
 struct tls_crypto_info_keys tls12;
 int one = 1;
 int ret;

 if (fips_enabled && variant->fips_non_compliant)
  SKIP(return"Unsupported cipher in FIPS mode");

 tls_crypto_info_init(variant->tls_version, variant->cipher_type,
        &tls12, 0);

 ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);

 if (self->notls)
  return;

 ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len);
 ASSERT_EQ(ret, 0);

 ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len);
 ASSERT_EQ(ret, 0);

 if (variant->nopad) {
  ret = setsockopt(self->cfd, SOL_TLS, TLS_RX_EXPECT_NO_PAD,
     (void *)&one, sizeof(one));
  ASSERT_EQ(ret, 0);
 }
}

FIXTURE_TEARDOWN(tls)
{
 close(self->fd);
 close(self->cfd);
}

TEST_F(tls, sendfile)
{
 int filefd = open("/proc/self/exe", O_RDONLY);
 struct stat st;

 EXPECT_GE(filefd, 0);
 fstat(filefd, &st);
 EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
}

TEST_F(tls, send_then_sendfile)
{
 int filefd = open("/proc/self/exe", O_RDONLY);
 char const *test_str = "test_send";
 int to_send = strlen(test_str) + 1;
 char recv_buf[10];
 struct stat st;
 char *buf;

 EXPECT_GE(filefd, 0);
 fstat(filefd, &st);
 buf = (char *)malloc(st.st_size);

 EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send);
 EXPECT_EQ(recv(self->cfd, recv_buf, to_send, MSG_WAITALL), to_send);
 EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0);

 EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
 EXPECT_EQ(recv(self->cfd, buf, st.st_size, MSG_WAITALL), st.st_size);
}

static void chunked_sendfile(struct __test_metadata *_metadata,
        struct _test_data_tls *self,
        uint16_t chunk_size,
        uint16_t extra_payload_size)
{
 char buf[TLS_PAYLOAD_MAX_LEN];
 uint16_t test_payload_size;
 int size = 0;
 int ret;
 char filename[] = "/tmp/mytemp.XXXXXX";
 int fd = mkstemp(filename);
 off_t offset = 0;

 unlink(filename);
 ASSERT_GE(fd, 0);
 EXPECT_GE(chunk_size, 1);
 test_payload_size = chunk_size + extra_payload_size;
 ASSERT_GE(TLS_PAYLOAD_MAX_LEN, test_payload_size);
 memset(buf, 1, test_payload_size);
 size = write(fd, buf, test_payload_size);
 EXPECT_EQ(size, test_payload_size);
 fsync(fd);

 while (size > 0) {
  ret = sendfile(self->fd, fd, &offset, chunk_size);
  EXPECT_GE(ret, 0);
  size -= ret;
 }

 EXPECT_EQ(recv(self->cfd, buf, test_payload_size, MSG_WAITALL),
    test_payload_size);

 close(fd);
}

TEST_F(tls, multi_chunk_sendfile)
{
 chunked_sendfile(_metadata, self, 4096, 4096);
 chunked_sendfile(_metadata, self, 4096, 0);
 chunked_sendfile(_metadata, self, 4096, 1);
 chunked_sendfile(_metadata, self, 4096, 2048);
 chunked_sendfile(_metadata, self, 8192, 2048);
 chunked_sendfile(_metadata, self, 4096, 8192);
 chunked_sendfile(_metadata, self, 8192, 4096);
 chunked_sendfile(_metadata, self, 12288, 1024);
 chunked_sendfile(_metadata, self, 12288, 2000);
 chunked_sendfile(_metadata, self, 15360, 100);
 chunked_sendfile(_metadata, self, 15360, 300);
 chunked_sendfile(_metadata, self, 1, 4096);
 chunked_sendfile(_metadata, self, 2048, 4096);
 chunked_sendfile(_metadata, self, 2048, 8192);
 chunked_sendfile(_metadata, self, 4096, 8192);
 chunked_sendfile(_metadata, self, 1024, 12288);
 chunked_sendfile(_metadata, self, 2000, 12288);
 chunked_sendfile(_metadata, self, 100, 15360);
 chunked_sendfile(_metadata, self, 300, 15360);
}

TEST_F(tls, recv_max)
{
 unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
 char recv_mem[TLS_PAYLOAD_MAX_LEN];
 char buf[TLS_PAYLOAD_MAX_LEN];

 memrnd(buf, sizeof(buf));

 EXPECT_GE(send(self->fd, buf, send_len, 0), 0);
 EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, recv_mem, send_len), 0);
}

TEST_F(tls, recv_small)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];

 send_len = strlen(test_str) + 1;
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}

TEST_F(tls, msg_more)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10 * 2];

 EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_WAITALL),
    send_len * 2);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}

TEST_F(tls, msg_more_unsent)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];

 EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
}

TEST_F(tls, msg_eor)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];

 EXPECT_EQ(send(self->fd, test_str, send_len, MSG_EOR), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}

TEST_F(tls, sendmsg_single)
{
 struct msghdr msg;

 char const *test_str = "test_sendmsg";
 size_t send_len = 13;
 struct iovec vec;
 char buf[13];

 vec.iov_base = (char *)test_str;
 vec.iov_len = send_len;
 memset(&msg, 0, sizeof(struct msghdr));
 msg.msg_iov = &vec;
 msg.msg_iovlen = 1;
 EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}

#define MAX_FRAGS 64
#define SEND_LEN 13
TEST_F(tls, sendmsg_fragmented)
{
 char const *test_str = "test_sendmsg";
 char buf[SEND_LEN * MAX_FRAGS];
 struct iovec vec[MAX_FRAGS];
 struct msghdr msg;
 int i, frags;

 for (frags = 1; frags <= MAX_FRAGS; frags++) {
  for (i = 0; i < frags; i++) {
   vec[i].iov_base = (char *)test_str;
   vec[i].iov_len = SEND_LEN;
  }

  memset(&msg, 0, sizeof(struct msghdr));
  msg.msg_iov = vec;
  msg.msg_iovlen = frags;

  EXPECT_EQ(sendmsg(self->fd, &msg, 0), SEND_LEN * frags);
  EXPECT_EQ(recv(self->cfd, buf, SEND_LEN * frags, MSG_WAITALL),
     SEND_LEN * frags);

  for (i = 0; i < frags; i++)
   EXPECT_EQ(memcmp(buf + SEND_LEN * i,
      test_str, SEND_LEN), 0);
 }
}
#undef MAX_FRAGS
#undef SEND_LEN

TEST_F(tls, sendmsg_large)
{
 void *mem = malloc(16384);
 size_t send_len = 16384;
 size_t sends = 128;
 struct msghdr msg;
 size_t recvs = 0;
 size_t sent = 0;

 memset(&msg, 0, sizeof(struct msghdr));
 while (sent++ < sends) {
  struct iovec vec = { (void *)mem, send_len };

  msg.msg_iov = &vec;
  msg.msg_iovlen = 1;
  EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
 }

 while (recvs++ < sends) {
  EXPECT_NE(recv(self->cfd, mem, send_len, 0), -1);
 }

 free(mem);
}

TEST_F(tls, sendmsg_multiple)
{
 char const *test_str = "test_sendmsg_multiple";
 struct iovec vec[5];
 char *test_strs[5];
 struct msghdr msg;
 int total_len = 0;
 int len_cmp = 0;
 int iov_len = 5;
 char *buf;
 int i;

 memset(&msg, 0, sizeof(struct msghdr));
 for (i = 0; i < iov_len; i++) {
  test_strs[i] = (char *)malloc(strlen(test_str) + 1);
  snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
  vec[i].iov_base = (void *)test_strs[i];
  vec[i].iov_len = strlen(test_strs[i]) + 1;
  total_len += vec[i].iov_len;
 }
 msg.msg_iov = vec;
 msg.msg_iovlen = iov_len;

 EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
 buf = malloc(total_len);
 EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);
 for (i = 0; i < iov_len; i++) {
  EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp,
     strlen(test_strs[i])),
     0);
  len_cmp += strlen(buf + len_cmp) + 1;
 }
 for (i = 0; i < iov_len; i++)
  free(test_strs[i]);
 free(buf);
}

TEST_F(tls, sendmsg_multiple_stress)
{
 char const *test_str = "abcdefghijklmno";
 struct iovec vec[1024];
 char *test_strs[1024];
 int iov_len = 1024;
 int total_len = 0;
 char buf[1 << 14];
 struct msghdr msg;
 int len_cmp = 0;
 int i;

 memset(&msg, 0, sizeof(struct msghdr));
 for (i = 0; i < iov_len; i++) {
  test_strs[i] = (char *)malloc(strlen(test_str) + 1);
  snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
  vec[i].iov_base = (void *)test_strs[i];
  vec[i].iov_len = strlen(test_strs[i]) + 1;
  total_len += vec[i].iov_len;
 }
 msg.msg_iov = vec;
 msg.msg_iovlen = iov_len;

 EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
 EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);

 for (i = 0; i < iov_len; i++)
  len_cmp += strlen(buf + len_cmp) + 1;

 for (i = 0; i < iov_len; i++)
  free(test_strs[i]);
}

TEST_F(tls, splice_from_pipe)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 int p[2];

 ASSERT_GE(pipe(p), 0);
 EXPECT_GE(write(p[1], mem_send, send_len), 0);
 EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0);
 EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len);
 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
}

TEST_F(tls, splice_more)
{
 unsigned int f = SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_GIFT;
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 int i, send_pipe = 1;
 int p[2];

 ASSERT_GE(pipe(p), 0);
 EXPECT_GE(write(p[1], mem_send, send_len), 0);
 for (i = 0; i < 32; i++)
  EXPECT_EQ(splice(p[0], NULL, self->fd, NULL, send_pipe, f), 1);
}

TEST_F(tls, splice_from_pipe2)
{
 int send_len = 16000;
 char mem_send[16000];
 char mem_recv[16000];
 int p2[2];
 int p[2];

 memrnd(mem_send, sizeof(mem_send));

 ASSERT_GE(pipe(p), 0);
 ASSERT_GE(pipe(p2), 0);
 EXPECT_EQ(write(p[1], mem_send, 8000), 8000);
 EXPECT_EQ(splice(p[0], NULL, self->fd, NULL, 8000, 0), 8000);
 EXPECT_EQ(write(p2[1], mem_send + 8000, 8000), 8000);
 EXPECT_EQ(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 8000);
 EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len);
 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
}

TEST_F(tls, send_and_splice)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 char const *test_str = "test_read";
 int send_len2 = 10;
 char buf[10];
 int p[2];

 ASSERT_GE(pipe(p), 0);
 EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2);
 EXPECT_EQ(recv(self->cfd, buf, send_len2, MSG_WAITALL), send_len2);
 EXPECT_EQ(memcmp(test_str, buf, send_len2), 0);

 EXPECT_GE(write(p[1], mem_send, send_len), send_len);
 EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len);

 EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len);
 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
}

TEST_F(tls, splice_to_pipe)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 int p[2];

 memrnd(mem_send, sizeof(mem_send));

 ASSERT_GE(pipe(p), 0);
 EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
 EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, send_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, splice_cmsg_to_pipe)
{
 char *test_str = "test_read";
 char record_type = 100;
 int send_len = 10;
 char buf[10];
 int p[2];

 if (self->notls)
  SKIP(return"no TLS support");

 ASSERT_GE(pipe(p), 0);
 EXPECT_EQ(tls_send_cmsg(self->fd, 100, test_str, send_len, 0), 10);
 EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, send_len, 0), -1);
 EXPECT_EQ(errno, EINVAL);
 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(errno, EIO);
 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, record_type,
    buf, sizeof(buf), MSG_WAITALL),
    send_len);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
}

TEST_F(tls, splice_dec_cmsg_to_pipe)
{
 char *test_str = "test_read";
 char record_type = 100;
 int send_len = 10;
 char buf[10];
 int p[2];

 if (self->notls)
  SKIP(return"no TLS support");

 ASSERT_GE(pipe(p), 0);
 EXPECT_EQ(tls_send_cmsg(self->fd, 100, test_str, send_len, 0), 10);
 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(errno, EIO);
 EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, send_len, 0), -1);
 EXPECT_EQ(errno, EINVAL);
 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, record_type,
    buf, sizeof(buf), MSG_WAITALL),
    send_len);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
}

TEST_F(tls, recv_and_splice)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 int half = send_len / 2;
 int p[2];

 ASSERT_GE(pipe(p), 0);
 EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
 /* Recv hald of the record, splice the other half */
 EXPECT_EQ(recv(self->cfd, mem_recv, half, MSG_WAITALL), half);
 EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, half, SPLICE_F_NONBLOCK),
    half);
 EXPECT_EQ(read(p[0], &mem_recv[half], half), half);
 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
}

TEST_F(tls, peek_and_splice)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char mem_send[TLS_PAYLOAD_MAX_LEN];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 int chunk = TLS_PAYLOAD_MAX_LEN / 4;
 int n, i, p[2];

 memrnd(mem_send, sizeof(mem_send));

 ASSERT_GE(pipe(p), 0);
 for (i = 0; i < 4; i++)
  EXPECT_EQ(send(self->fd, &mem_send[chunk * i], chunk, 0),
     chunk);

 EXPECT_EQ(recv(self->cfd, mem_recv, chunk * 5 / 2,
         MSG_WAITALL | MSG_PEEK),
    chunk * 5 / 2);
 EXPECT_EQ(memcmp(mem_send, mem_recv, chunk * 5 / 2), 0);

 n = 0;
 while (n < send_len) {
  i = splice(self->cfd, NULL, p[1], NULL, send_len - n, 0);
  EXPECT_GT(i, 0);
  n += i;
 }
 EXPECT_EQ(n, 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, recvmsg_single)
{
 char const *test_str = "test_recvmsg_single";
 int send_len = strlen(test_str) + 1;
 char buf[20];
 struct msghdr hdr;
 struct iovec vec;

 memset(&hdr, 0, sizeof(hdr));
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 vec.iov_base = (char *)buf;
 vec.iov_len = send_len;
 hdr.msg_iovlen = 1;
 hdr.msg_iov = &vec;
 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
}

TEST_F(tls, recvmsg_single_max)
{
 int send_len = TLS_PAYLOAD_MAX_LEN;
 char send_mem[TLS_PAYLOAD_MAX_LEN];
 char recv_mem[TLS_PAYLOAD_MAX_LEN];
 struct iovec vec;
 struct msghdr hdr;

 memrnd(send_mem, sizeof(send_mem));

 EXPECT_EQ(send(self->fd, send_mem, send_len, 0), send_len);
 vec.iov_base = (char *)recv_mem;
 vec.iov_len = TLS_PAYLOAD_MAX_LEN;

 hdr.msg_iovlen = 1;
 hdr.msg_iov = &vec;
 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
 EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
}

TEST_F(tls, recvmsg_multiple)
{
 unsigned int msg_iovlen = 1024;
 struct iovec vec[1024];
 char *iov_base[1024];
 unsigned int iov_len = 16;
 int send_len = 1 << 14;
 char buf[1 << 14];
 struct msghdr hdr;
 int i;

 memrnd(buf, sizeof(buf));

 EXPECT_EQ(send(self->fd, buf, send_len, 0), send_len);
 for (i = 0; i < msg_iovlen; i++) {
  iov_base[i] = (char *)malloc(iov_len);
  vec[i].iov_base = iov_base[i];
  vec[i].iov_len = iov_len;
 }

 hdr.msg_iovlen = msg_iovlen;
 hdr.msg_iov = vec;
 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);

 for (i = 0; i < msg_iovlen; i++)
  free(iov_base[i]);
}

TEST_F(tls, single_send_multiple_recv)
{
 unsigned int total_len = TLS_PAYLOAD_MAX_LEN * 2;
 unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
 char send_mem[TLS_PAYLOAD_MAX_LEN * 2];
 char recv_mem[TLS_PAYLOAD_MAX_LEN * 2];

 memrnd(send_mem, sizeof(send_mem));

 EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0);
 memset(recv_mem, 0, total_len);

 EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
 EXPECT_NE(recv(self->cfd, recv_mem + send_len, send_len, 0), -1);
 EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0);
}

TEST_F(tls, multiple_send_single_recv)
{
 unsigned int total_len = 2 * 10;
 unsigned int send_len = 10;
 char recv_mem[2 * 10];
 char send_mem[10];

 memrnd(send_mem, sizeof(send_mem));

 EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
 EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
 memset(recv_mem, 0, total_len);
 EXPECT_EQ(recv(self->cfd, recv_mem, total_len, MSG_WAITALL), total_len);

 EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
 EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0);
}

TEST_F(tls, single_send_multiple_recv_non_align)
{
 const unsigned int total_len = 15;
 const unsigned int recv_len = 10;
 char recv_mem[recv_len * 2];
 char send_mem[total_len];

 memrnd(send_mem, sizeof(send_mem));

 EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0);
 memset(recv_mem, 0, total_len);

 EXPECT_EQ(recv(self->cfd, recv_mem, recv_len, 0), recv_len);
 EXPECT_EQ(recv(self->cfd, recv_mem + recv_len, recv_len, 0), 5);
 EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0);
}

TEST_F(tls, recv_partial)
{
 char const *test_str = "test_read_partial";
 char const *test_str_first = "test_read";
 char const *test_str_second = "_partial";
 int send_len = strlen(test_str) + 1;
 char recv_mem[18];

 memset(recv_mem, 0, sizeof(recv_mem));
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_first),
         MSG_WAITALL), strlen(test_str_first));
 EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0);
 memset(recv_mem, 0, sizeof(recv_mem));
 EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_second),
         MSG_WAITALL), strlen(test_str_second));
 EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)),
    0);
}

TEST_F(tls, recv_nonblock)
{
 char buf[4096];
 bool err;

 EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
 err = (errno == EAGAIN || errno == EWOULDBLOCK);
 EXPECT_EQ(err, true);
}

TEST_F(tls, recv_peek)
{
 char const *test_str = "test_read_peek";
 int send_len = strlen(test_str) + 1;
 char buf[15];

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_PEEK), send_len);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
 memset(buf, 0, sizeof(buf));
 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
}

TEST_F(tls, recv_peek_multiple)
{
 char const *test_str = "test_read_peek";
 int send_len = strlen(test_str) + 1;
 unsigned int num_peeks = 100;
 char buf[15];
 int i;

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 for (i = 0; i < num_peeks; i++) {
  EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
  EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
  memset(buf, 0, sizeof(buf));
 }
 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
}

TEST_F(tls, recv_peek_multiple_records)
{
 char const *test_str = "test_read_peek_mult_recs";
 char const *test_str_first = "test_read_peek";
 char const *test_str_second = "_mult_recs";
 int len;
 char buf[64];

 len = strlen(test_str_first);
 EXPECT_EQ(send(self->fd, test_str_first, len, 0), len);

 len = strlen(test_str_second) + 1;
 EXPECT_EQ(send(self->fd, test_str_second, len, 0), len);

 len = strlen(test_str_first);
 memset(buf, 0, len);
 EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len);

 /* MSG_PEEK can only peek into the current record. */
 len = strlen(test_str_first);
 EXPECT_EQ(memcmp(test_str_first, buf, len), 0);

 len = strlen(test_str) + 1;
 memset(buf, 0, len);
 EXPECT_EQ(recv(self->cfd, buf, len, MSG_WAITALL), len);

 /* Non-MSG_PEEK will advance strparser (and therefore record)
 * however.
 */

 len = strlen(test_str) + 1;
 EXPECT_EQ(memcmp(test_str, buf, len), 0);

 /* MSG_MORE will hold current record open, so later MSG_PEEK
 * will see everything.
 */

 len = strlen(test_str_first);
 EXPECT_EQ(send(self->fd, test_str_first, len, MSG_MORE), len);

 len = strlen(test_str_second) + 1;
 EXPECT_EQ(send(self->fd, test_str_second, len, 0), len);

 len = strlen(test_str) + 1;
 memset(buf, 0, len);
 EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len);

 len = strlen(test_str) + 1;
 EXPECT_EQ(memcmp(test_str, buf, len), 0);
}

TEST_F(tls, recv_peek_large_buf_mult_recs)
{
 char const *test_str = "test_read_peek_mult_recs";
 char const *test_str_first = "test_read_peek";
 char const *test_str_second = "_mult_recs";
 int len;
 char buf[64];

 len = strlen(test_str_first);
 EXPECT_EQ(send(self->fd, test_str_first, len, 0), len);

 len = strlen(test_str_second) + 1;
 EXPECT_EQ(send(self->fd, test_str_second, len, 0), len);

 len = strlen(test_str) + 1;
 memset(buf, 0, len);
 EXPECT_NE((len = recv(self->cfd, buf, len,
         MSG_PEEK | MSG_WAITALL)), -1);
 len = strlen(test_str) + 1;
 EXPECT_EQ(memcmp(test_str, buf, len), 0);
}

TEST_F(tls, recv_lowat)
{
 char send_mem[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 char recv_mem[20];
 int lowat = 8;

 EXPECT_EQ(send(self->fd, send_mem, 10, 0), 10);
 EXPECT_EQ(send(self->fd, send_mem, 5, 0), 5);

 memset(recv_mem, 0, 20);
 EXPECT_EQ(setsockopt(self->cfd, SOL_SOCKET, SO_RCVLOWAT,
        &lowat, sizeof(lowat)), 0);
 EXPECT_EQ(recv(self->cfd, recv_mem, 1, MSG_WAITALL), 1);
 EXPECT_EQ(recv(self->cfd, recv_mem + 1, 6, MSG_WAITALL), 6);
 EXPECT_EQ(recv(self->cfd, recv_mem + 7, 10, 0), 8);

 EXPECT_EQ(memcmp(send_mem, recv_mem, 10), 0);
 EXPECT_EQ(memcmp(send_mem, recv_mem + 10, 5), 0);
}

TEST_F(tls, bidir)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];
 int ret;

 if (!self->notls) {
  struct tls_crypto_info_keys tls12;

  tls_crypto_info_init(variant->tls_version, variant->cipher_type,
         &tls12, 0);

  ret = setsockopt(self->fd, SOL_TLS, TLS_RX, &tls12,
     tls12.len);
  ASSERT_EQ(ret, 0);

  ret = setsockopt(self->cfd, SOL_TLS, TLS_TX, &tls12,
     tls12.len);
  ASSERT_EQ(ret, 0);
 }

 ASSERT_EQ(strlen(test_str) + 1, send_len);

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);

 memset(buf, 0, sizeof(buf));

 EXPECT_EQ(send(self->cfd, test_str, send_len, 0), send_len);
 EXPECT_NE(recv(self->fd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
};

TEST_F(tls, pollin)
{
 char const *test_str = "test_poll";
 struct pollfd fd = { 0, 0, 0 };
 char buf[10];
 int send_len = 10;

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 fd.fd = self->cfd;
 fd.events = POLLIN;

 EXPECT_EQ(poll(&fd, 1, 20), 1);
 EXPECT_EQ(fd.revents & POLLIN, 1);
 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len);
 /* Test timing out */
 EXPECT_EQ(poll(&fd, 1, 20), 0);
}

TEST_F(tls, poll_wait)
{
 char const *test_str = "test_poll_wait";
 int send_len = strlen(test_str) + 1;
 struct pollfd fd = { 0, 0, 0 };
 char recv_mem[15];

 fd.fd = self->cfd;
 fd.events = POLLIN;
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 /* Set timeout to inf. secs */
 EXPECT_EQ(poll(&fd, 1, -1), 1);
 EXPECT_EQ(fd.revents & POLLIN, 1);
 EXPECT_EQ(recv(self->cfd, recv_mem, send_len, MSG_WAITALL), send_len);
}

TEST_F(tls, poll_wait_split)
{
 struct pollfd fd = { 0, 0, 0 };
 char send_mem[20] = {};
 char recv_mem[15];

 fd.fd = self->cfd;
 fd.events = POLLIN;
 /* Send 20 bytes */
 EXPECT_EQ(send(self->fd, send_mem, sizeof(send_mem), 0),
    sizeof(send_mem));
 /* Poll with inf. timeout */
 EXPECT_EQ(poll(&fd, 1, -1), 1);
 EXPECT_EQ(fd.revents & POLLIN, 1);
 EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), MSG_WAITALL),
    sizeof(recv_mem));

 /* Now the remaining 5 bytes of record data are in TLS ULP */
 fd.fd = self->cfd;
 fd.events = POLLIN;
 EXPECT_EQ(poll(&fd, 1, -1), 1);
 EXPECT_EQ(fd.revents & POLLIN, 1);
 EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), 0),
    sizeof(send_mem) - sizeof(recv_mem));
}

TEST_F(tls, blocking)
{
 size_t data = 100000;
 int res = fork();

 EXPECT_NE(res, -1);

 if (res) {
  /* parent */
  size_t left = data;
  char buf[16384];
  int status;
  int pid2;

  while (left) {
   int res = send(self->fd, buf,
           left > 16384 ? 16384 : left, 0);

   EXPECT_GE(res, 0);
   left -= res;
  }

  pid2 = wait(&status);
  EXPECT_EQ(status, 0);
  EXPECT_EQ(res, pid2);
 } else {
  /* child */
  size_t left = data;
  char buf[16384];

  while (left) {
   int res = recv(self->cfd, buf,
           left > 16384 ? 16384 : left, 0);

   EXPECT_GE(res, 0);
   left -= res;
  }
 }
}

TEST_F(tls, nonblocking)
{
 size_t data = 100000;
 int sendbuf = 100;
 int flags;
 int res;

 flags = fcntl(self->fd, F_GETFL, 0);
 fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
 fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK);

 /* Ensure nonblocking behavior by imposing a small send
 * buffer.
 */

 EXPECT_EQ(setsockopt(self->fd, SOL_SOCKET, SO_SNDBUF,
        &sendbuf, sizeof(sendbuf)), 0);

 res = fork();
 EXPECT_NE(res, -1);

 if (res) {
  /* parent */
  bool eagain = false;
  size_t left = data;
  char buf[16384];
  int status;
  int pid2;

  while (left) {
   int res = send(self->fd, buf,
           left > 16384 ? 16384 : left, 0);

   if (res == -1 && errno == EAGAIN) {
    eagain = true;
    usleep(10000);
    continue;
   }
   EXPECT_GE(res, 0);
   left -= res;
  }

  EXPECT_TRUE(eagain);
  pid2 = wait(&status);

  EXPECT_EQ(status, 0);
  EXPECT_EQ(res, pid2);
 } else {
  /* child */
  bool eagain = false;
  size_t left = data;
  char buf[16384];

  while (left) {
   int res = recv(self->cfd, buf,
           left > 16384 ? 16384 : left, 0);

   if (res == -1 && errno == EAGAIN) {
    eagain = true;
    usleep(10000);
    continue;
   }
   EXPECT_GE(res, 0);
   left -= res;
  }
  EXPECT_TRUE(eagain);
 }
}

static void
test_mutliproc(struct __test_metadata *_metadata, struct _test_data_tls *self,
        bool sendpg, unsigned int n_readers, unsigned int n_writers)
{
 const unsigned int n_children = n_readers + n_writers;
 const size_t data = 6 * 1000 * 1000;
 const size_t file_sz = data / 100;
 size_t read_bias, write_bias;
 int i, fd, child_id;
 char buf[file_sz];
 pid_t pid;

 /* Only allow multiples for simplicity */
 ASSERT_EQ(!(n_readers % n_writers) || !(n_writers % n_readers), true);
 read_bias = n_writers / n_readers ?: 1;
 write_bias = n_readers / n_writers ?: 1;

 /* prep a file to send */
 fd = open("/tmp/", O_TMPFILE | O_RDWR, 0600);
 ASSERT_GE(fd, 0);

 memset(buf, 0xac, file_sz);
 ASSERT_EQ(write(fd, buf, file_sz), file_sz);

 /* spawn children */
 for (child_id = 0; child_id < n_children; child_id++) {
  pid = fork();
  ASSERT_NE(pid, -1);
  if (!pid)
   break;
 }

 /* parent waits for all children */
 if (pid) {
  for (i = 0; i < n_children; i++) {
   int status;

   wait(&status);
   EXPECT_EQ(status, 0);
  }

  return;
 }

 /* Split threads for reading and writing */
 if (child_id < n_readers) {
  size_t left = data * read_bias;
  char rb[8001];

  while (left) {
   int res;

   res = recv(self->cfd, rb,
       left > sizeof(rb) ? sizeof(rb) : left, 0);

   EXPECT_GE(res, 0);
   left -= res;
  }
 } else {
  size_t left = data * write_bias;

  while (left) {
   int res;

   ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
   if (sendpg)
    res = sendfile(self->fd, fd, NULL,
            left > file_sz ? file_sz : left);
   else
    res = send(self->fd, buf,
        left > file_sz ? file_sz : left, 0);

   EXPECT_GE(res, 0);
   left -= res;
  }
 }
}

TEST_F(tls, mutliproc_even)
{
 test_mutliproc(_metadata, self, false, 6, 6);
}

TEST_F(tls, mutliproc_readers)
{
 test_mutliproc(_metadata, self, false, 4, 12);
}

TEST_F(tls, mutliproc_writers)
{
 test_mutliproc(_metadata, self, false, 10, 2);
}

TEST_F(tls, mutliproc_sendpage_even)
{
 test_mutliproc(_metadata, self, true, 6, 6);
}

TEST_F(tls, mutliproc_sendpage_readers)
{
 test_mutliproc(_metadata, self, true, 4, 12);
}

TEST_F(tls, mutliproc_sendpage_writers)
{
 test_mutliproc(_metadata, self, true, 10, 2);
}

TEST_F(tls, control_msg)
{
 char *test_str = "test_read";
 char record_type = 100;
 int send_len = 10;
 char buf[10];

 if (self->notls)
  SKIP(return"no TLS support");

 EXPECT_EQ(tls_send_cmsg(self->fd, record_type, test_str, send_len, 0),
    send_len);
 /* Should fail because we didn't provide a control message */
 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, record_type,
    buf, sizeof(buf), MSG_WAITALL | MSG_PEEK),
    send_len);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);

 /* Recv the message again without MSG_PEEK */
 memset(buf, 0, sizeof(buf));

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, record_type,
    buf, sizeof(buf), MSG_WAITALL),
    send_len);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}

TEST_F(tls, control_msg_nomerge)
{
 char *rec1 = "1111";
 char *rec2 = "2222";
 int send_len = 5;
 char buf[15];

 if (self->notls)
  SKIP(return"no TLS support");

 EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec1, send_len, 0), send_len);
 EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec2, send_len, 0), send_len);

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), MSG_PEEK), send_len);
 EXPECT_EQ(memcmp(buf, rec1, send_len), 0);

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), MSG_PEEK), send_len);
 EXPECT_EQ(memcmp(buf, rec1, send_len), 0);

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), 0), send_len);
 EXPECT_EQ(memcmp(buf, rec1, send_len), 0);

 EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), 0), send_len);
 EXPECT_EQ(memcmp(buf, rec2, send_len), 0);
}

TEST_F(tls, data_control_data)
{
 char *rec1 = "1111";
 char *rec2 = "2222";
 char *rec3 = "3333";
 int send_len = 5;
 char buf[15];

 if (self->notls)
  SKIP(return"no TLS support");

 EXPECT_EQ(send(self->fd, rec1, send_len, 0), send_len);
 EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec2, send_len, 0), send_len);
 EXPECT_EQ(send(self->fd, rec3, send_len, 0), send_len);

 EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
 EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
}

TEST_F(tls, shutdown)
{
 char const *test_str = "test_read";
 int send_len = 10;
 char buf[10];

 ASSERT_EQ(strlen(test_str) + 1, send_len);

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);

 shutdown(self->fd, SHUT_RDWR);
 shutdown(self->cfd, SHUT_RDWR);
}

TEST_F(tls, shutdown_unsent)
{
 char const *test_str = "test_read";
 int send_len = 10;

 EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);

 shutdown(self->fd, SHUT_RDWR);
 shutdown(self->cfd, SHUT_RDWR);
}

TEST_F(tls, shutdown_reuse)
{
 struct sockaddr_in addr;
 int ret;

 shutdown(self->fd, SHUT_RDWR);
 shutdown(self->cfd, SHUT_RDWR);
 close(self->cfd);

 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 addr.sin_port = 0;

 ret = bind(self->fd, &addr, sizeof(addr));
 EXPECT_EQ(ret, 0);
 ret = listen(self->fd, 10);
 EXPECT_EQ(ret, -1);
 EXPECT_EQ(errno, EINVAL);

 ret = connect(self->fd, &addr, sizeof(addr));
 EXPECT_EQ(ret, -1);
 EXPECT_EQ(errno, EISCONN);
}

TEST_F(tls, getsockopt)
{
 struct tls_crypto_info_keys expect, get;
 socklen_t len;

 /* get only the version/cipher */
 len = sizeof(struct tls_crypto_info);
 memrnd(&get, sizeof(get));
 EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), 0);
 EXPECT_EQ(len, sizeof(struct tls_crypto_info));
 EXPECT_EQ(get.crypto_info.version, variant->tls_version);
 EXPECT_EQ(get.crypto_info.cipher_type, variant->cipher_type);

 /* get the full crypto_info */
 tls_crypto_info_init(variant->tls_version, variant->cipher_type, &expect, 0);
 len = expect.len;
 memrnd(&get, sizeof(get));
 EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), 0);
 EXPECT_EQ(len, expect.len);
 EXPECT_EQ(get.crypto_info.version, variant->tls_version);
 EXPECT_EQ(get.crypto_info.cipher_type, variant->cipher_type);
 EXPECT_EQ(memcmp(&get, &expect, expect.len), 0);

 /* short get should fail */
 len = sizeof(struct tls_crypto_info) - 1;
 EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), -1);
 EXPECT_EQ(errno, EINVAL);

 /* partial get of the cipher data should fail */
 len = expect.len - 1;
 EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &get, &len), -1);
 EXPECT_EQ(errno, EINVAL);
}

TEST_F(tls, recv_efault)
{
 char *rec1 = "1111111111";
 char *rec2 = "2222222222";
 struct msghdr hdr = {};
 struct iovec iov[2];
 char recv_mem[12];
 int ret;

 if (self->notls)
  SKIP(return"no TLS support");

 EXPECT_EQ(send(self->fd, rec1, 10, 0), 10);
 EXPECT_EQ(send(self->fd, rec2, 10, 0), 10);

 iov[0].iov_base = recv_mem;
 iov[0].iov_len = sizeof(recv_mem);
 iov[1].iov_base = NULL; /* broken iov to make process_rx_list fail */
 iov[1].iov_len = 1;

 hdr.msg_iovlen = 2;
 hdr.msg_iov = iov;

 EXPECT_EQ(recv(self->cfd, recv_mem, 1, 0), 1);
 EXPECT_EQ(recv_mem[0], rec1[0]);

 ret = recvmsg(self->cfd, &hdr, 0);
 EXPECT_LE(ret, sizeof(recv_mem));
 EXPECT_GE(ret, 9);
 EXPECT_EQ(memcmp(rec1, recv_mem, 9), 0);
 if (ret > 9)
  EXPECT_EQ(memcmp(rec2, recv_mem + 9, ret - 9), 0);
}

#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_basic, disconnect)
{
 char const *test_str = "test_message";
 int send_len = strlen(test_str) + 1;
 struct tls_crypto_info_keys key;
 struct sockaddr_in addr;
 char buf[20];
 int ret;

 if (self->notls)
  return;

 tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
        &key, 0);

 ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &key, key.len);
 ASSERT_EQ(ret, 0);

 /* Pre-queue the data so that setsockopt parses it but doesn't
 * dequeue it from the TCP socket. recvmsg would dequeue.
 */

 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);

 ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &key, key.len);
 ASSERT_EQ(ret, 0);

 addr.sin_family = AF_UNSPEC;
 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 addr.sin_port = 0;
 ret = connect(self->cfd, &addr, sizeof(addr));
 EXPECT_EQ(ret, -1);
 EXPECT_EQ(errno, EOPNOTSUPP);

 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
}

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_fail)
{
 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];

 /* 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);

 if (variant->tls_version != TLS_1_3_VERSION) {
  /* just check that rekey is not supported and return */
  tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
  EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
  EXPECT_EQ(errno, EBUSY);
  return;
 }

 /* successful update */
 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);

 /* invalid update: change of version */
 tls_crypto_info_init(TLS_1_2_VERSION, variant->cipher_type, &tls12, 1);
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
 EXPECT_EQ(errno, EINVAL);

 /* invalid update (RX socket): change of version */
 tls_crypto_info_init(TLS_1_2_VERSION, variant->cipher_type, &tls12, 1);
 EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), -1);
 EXPECT_EQ(errno, EINVAL);

 /* invalid update: change of cipher */
 if (variant->cipher_type == TLS_CIPHER_AES_GCM_256)
  tls_crypto_info_init(variant->tls_version, TLS_CIPHER_CHACHA20_POLY1305, &tls12, 1);
 else
  tls_crypto_info_init(variant->tls_version, TLS_CIPHER_AES_GCM_256, &tls12, 1);
 EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
 EXPECT_EQ(errno, EINVAL);

 /* send after rekey, the invalid updates shouldn't have an effect */
 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 */
 tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
 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_peek_splice)
{
 char const *test_str_1 = "test_message_before_rekey";
 struct tls_crypto_info_keys tls12;
 int send_len;
 char buf[100];
 char mem_recv[TLS_PAYLOAD_MAX_LEN];
 int p[2];

 if (variant->tls_version != TLS_1_3_VERSION)
  return;

 ASSERT_GE(pipe(p), 0);

 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(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_recv, test_str_1, 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);
}

TEST_F(tls, rekey_poll_pending)
{
 char const *test_str = "test_message_after_rekey";
 struct tls_crypto_info_keys tls12;
 struct pollfd pfd = { };
 int send_len;
 int ret;

 if (variant->tls_version != TLS_1_3_VERSION)
  return;

 /* 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);

 /* get KeyUpdate */
 tls_recv_keyupdate(_metadata, self->cfd, 0);

 /* send immediately after rekey */
 send_len = strlen(test_str) + 1;
 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);

 /* key hasn't been updated, expect cfd to be non-readable */
 pfd.fd = self->cfd;
 pfd.events = POLLIN;
 EXPECT_EQ(poll(&pfd, 1, 0), 0);

 ret = fork();
 ASSERT_GE(ret, 0);

 if (ret) {
  int pid2, status;

  /* wait before installing the new key */
  sleep(1);

  /* update RX key while poll() is sleeping */
  EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);

  pid2 = wait(&status);
  EXPECT_EQ(pid2, ret);
  EXPECT_EQ(status, 0);
 } else {
  pfd.fd = self->cfd;
  pfd.events = POLLIN;
  EXPECT_EQ(poll(&pfd, 1, 5000), 1);

  exit(!__test_passed(_metadata));
 }
}

TEST_F(tls, rekey_poll_delay)
{
 char const *test_str = "test_message_after_rekey";
 struct tls_crypto_info_keys tls12;
 struct pollfd pfd = { };
 int send_len;
 int ret;

 if (variant->tls_version != TLS_1_3_VERSION)
  return;

 /* 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);

 /* get KeyUpdate */
 tls_recv_keyupdate(_metadata, self->cfd, 0);

 ret = fork();
 ASSERT_GE(ret, 0);

 if (ret) {
  int pid2, status;

  /* wait before installing the new key */
  sleep(1);

  /* update RX key while poll() is sleeping */
  EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);

  sleep(1);
  send_len = strlen(test_str) + 1;
  EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);

  pid2 = wait(&status);
  EXPECT_EQ(pid2, ret);
  EXPECT_EQ(status, 0);
 } else {
  pfd.fd = self->cfd;
  pfd.events = POLLIN;
  EXPECT_EQ(poll(&pfd, 1, 5000), 1);
  exit(!__test_passed(_metadata));
 }
}

struct raw_rec {
 unsigned int plain_len;
 unsigned char plain_data[100];
 unsigned int cipher_len;
 unsigned char cipher_data[128];
};

/* TLS 1.2, AES_CCM, data, seqno:0, plaintext: 'Hello world' */
static const struct raw_rec id0_data_l11 = {
 .plain_len = 11,
 .plain_data = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
  0x72, 0x6c, 0x64,
 },
 .cipher_len = 40,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xa2, 0x33,
  0xde, 0x8d, 0x94, 0xf0, 0x29, 0x6c, 0xb1, 0xaf,
  0x6a, 0x75, 0xb2, 0x93, 0xad, 0x45, 0xd5, 0xfd,
  0x03, 0x51, 0x57, 0x8f, 0xf9, 0xcc, 0x3b, 0x42,
 },
};

/* TLS 1.2, AES_CCM, ctrl, seqno:0, plaintext: '' */
static const struct raw_rec id0_ctrl_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x38, 0x7b,
  0xa6, 0x1c, 0xdd, 0xa7, 0x19, 0x33, 0xab, 0xae,
  0x88, 0xe1, 0xd2, 0x08, 0x4f,
 },
};

/* TLS 1.2, AES_CCM, data, seqno:0, plaintext: '' */
static const struct raw_rec id0_data_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x37, 0x90,
  0x70, 0x45, 0x89, 0xfb, 0x5c, 0xc7, 0x89, 0x03,
  0x68, 0x80, 0xd3, 0xd8, 0xcc,
 },
};

/* TLS 1.2, AES_CCM, data, seqno:1, plaintext: 'Hello world' */
static const struct raw_rec id1_data_l11 = {
 .plain_len = 11,
 .plain_data = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
  0x72, 0x6c, 0x64,
 },
 .cipher_len = 40,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x1a, 0x9c,
  0xd0, 0xa8, 0x9a, 0xd6, 0x69, 0xd6, 0x1a, 0xe3,
  0xb5, 0x1f, 0x0d, 0x2c, 0xe2, 0x97, 0x46, 0xff,
  0x2b, 0xcc, 0x5a, 0xc4, 0xa3, 0xb9, 0xef, 0xba,
 },
};

/* TLS 1.2, AES_CCM, ctrl, seqno:1, plaintext: '' */
static const struct raw_rec id1_ctrl_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0xf0, 0xfe,
  0xee, 0xd9, 0xe2, 0x5d, 0xc7, 0x11, 0x4c, 0xe6,
  0xb4, 0x7e, 0xef, 0x40, 0x2b,
 },
};

/* TLS 1.2, AES_CCM, data, seqno:1, plaintext: '' */
static const struct raw_rec id1_data_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0xfc, 0x86,
  0xc8, 0xf0, 0x55, 0xf9, 0x47, 0x3f, 0x74, 0xdc,
  0xc9, 0xbf, 0xfe, 0x5b, 0xb1,
 },
};

/* TLS 1.2, AES_CCM, ctrl, seqno:2, plaintext: 'Hello world' */
static const struct raw_rec id2_ctrl_l11 = {
 .plain_len = 11,
 .plain_data = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
  0x72, 0x6c, 0x64,
 },
 .cipher_len = 40,
 .cipher_data = {
  0x16, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0xe5, 0x3d, 0x19,
  0x3d, 0xca, 0xb8, 0x16, 0xb6, 0xff, 0x79, 0x87,
  0x2a, 0x04, 0x11, 0x3d, 0xf8, 0x64, 0x5f, 0x36,
  0x8b, 0xa8, 0xee, 0x4c, 0x6d, 0x62, 0xa5, 0x00,
 },
};

/* TLS 1.2, AES_CCM, data, seqno:2, plaintext: 'Hello world' */
static const struct raw_rec id2_data_l11 = {
 .plain_len = 11,
 .plain_data = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f,
  0x72, 0x6c, 0x64,
 },
 .cipher_len = 40,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0xe5, 0x3d, 0x19,
  0x3d, 0xca, 0xb8, 0x16, 0xb6, 0xff, 0x79, 0x87,
  0x8e, 0xa1, 0xd0, 0xcd, 0x33, 0xb5, 0x86, 0x2b,
  0x17, 0xf1, 0x52, 0x2a, 0x55, 0x62, 0x65, 0x11,
 },
};

/* TLS 1.2, AES_CCM, ctrl, seqno:2, plaintext: '' */
static const struct raw_rec id2_ctrl_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x16, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0xdc, 0x5c, 0x0e,
  0x41, 0xdd, 0xba, 0xd3, 0xcc, 0xcf, 0x6d, 0xd9,
  0x06, 0xdb, 0x79, 0xe5, 0x5d,
 },
};

/* TLS 1.2, AES_CCM, data, seqno:2, plaintext: '' */
static const struct raw_rec id2_data_l0 = {
 .plain_len = 0,
 .plain_data = {
 },
 .cipher_len = 29,
 .cipher_data = {
  0x17, 0x03, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0xc3, 0xca, 0x26,
  0x22, 0xe4, 0x25, 0xfb, 0x5f, 0x6d, 0xbf, 0x83,
  0x30, 0x48, 0x69, 0x1a, 0x47,
 },
};

FIXTURE(zero_len)
{
 int fd, cfd;
 bool notls;
};

FIXTURE_VARIANT(zero_len)
{
 const struct raw_rec *recs[4];
 ssize_t recv_ret[4];
};

FIXTURE_VARIANT_ADD(zero_len, data_data_data)
{
 .recs = { &id0_data_l11, &id1_data_l11, &id2_data_l11, },
 .recv_ret = { 33, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, data_0ctrl_data)
{
 .recs = { &id0_data_l11, &id1_ctrl_l0, &id2_data_l11, },
 .recv_ret = { 11, 0, 11, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, 0data_0data_0data)
{
 .recs = { &id0_data_l0, &id1_data_l0, &id2_data_l0, },
 .recv_ret = { -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, 0data_0data_ctrl)
{
 .recs = { &id0_data_l0, &id1_data_l0, &id2_ctrl_l11, },
 .recv_ret = { 0, 11, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, 0data_0data_0ctrl)
{
 .recs = { &id0_data_l0, &id1_data_l0, &id2_ctrl_l0, },
 .recv_ret = { 0, 0, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, 0ctrl_0ctrl_0ctrl)
{
 .recs = { &id0_ctrl_l0, &id1_ctrl_l0, &id2_ctrl_l0, },
 .recv_ret = { 0, 0, 0, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, 0data_0data_data)
{
 .recs = { &id0_data_l0, &id1_data_l0, &id2_data_l11, },
 .recv_ret = { 11, -EAGAIN, },
};

FIXTURE_VARIANT_ADD(zero_len, data_0data_0data)
{
 .recs = { &id0_data_l11, &id1_data_l0, &id2_data_l0, },
 .recv_ret = { 11, -EAGAIN, },
};

FIXTURE_SETUP(zero_len)
{
 struct tls_crypto_info_keys tls12;
 int ret;

 tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_CCM_128,
        &tls12, 0);

 ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
 if (self->notls)
  return;

 /* Don't install keys on fd, we'll send raw records */
 ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len);
 ASSERT_EQ(ret, 0);
}

FIXTURE_TEARDOWN(zero_len)
{
 close(self->fd);
 close(self->cfd);
}

TEST_F(zero_len, test)
{
 const struct raw_rec *const *rec;
 unsigned char buf[128];
 int rec_off;
 int i;

 for (i = 0; i < 4 && variant->recs[i]; i++)
  EXPECT_EQ(send(self->fd, variant->recs[i]->cipher_data,
          variant->recs[i]->cipher_len, 0),
     variant->recs[i]->cipher_len);

 rec = &variant->recs[0];
 rec_off = 0;
 for (i = 0; i < 4; i++) {
  int j, ret;

  ret = variant->recv_ret[i] >= 0 ? variant->recv_ret[i] : -1;
  EXPECT_EQ(__tls_recv_cmsg(_metadata, self->cfd, NULL,
       buf, sizeof(buf), MSG_DONTWAIT), ret);
  if (ret == -1)
   EXPECT_EQ(errno, -variant->recv_ret[i]);
  if (variant->recv_ret[i] == -EAGAIN)
   break;

  for (j = 0; j < ret; j++) {
   while (rec_off == (*rec)->plain_len) {
    rec++;
    rec_off = 0;
   }
   EXPECT_EQ(buf[j], (*rec)->plain_data[rec_off]);
   rec_off++;
  }
 }
};

FIXTURE(tls_err)
{
 int fd, cfd;
 int fd2, cfd2;
 bool notls;
};

FIXTURE_VARIANT(tls_err)
{
 uint16_t tls_version;
};

FIXTURE_VARIANT_ADD(tls_err, 12_aes_gcm)
{
 .tls_version = TLS_1_2_VERSION,
};

FIXTURE_VARIANT_ADD(tls_err, 13_aes_gcm)
{
 .tls_version = TLS_1_3_VERSION,
};

FIXTURE_SETUP(tls_err)
{
 struct tls_crypto_info_keys tls12;
 int ret;

 tls_crypto_info_init(variant->tls_version, TLS_CIPHER_AES_GCM_128,
        &tls12, 0);

 ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
 ulp_sock_pair(_metadata, &self->fd2, &self->cfd2, &self->notls);
 if (self->notls)
  return;

 ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len);
 ASSERT_EQ(ret, 0);

 ret = setsockopt(self->cfd2, SOL_TLS, TLS_RX, &tls12, tls12.len);
 ASSERT_EQ(ret, 0);
}

FIXTURE_TEARDOWN(tls_err)
{
 close(self->fd);
 close(self->cfd);
 close(self->fd2);
 close(self->cfd2);
}

TEST_F(tls_err, bad_rec)
{
 char buf[64];

 if (self->notls)
  SKIP(return"no TLS support");

 memset(buf, 0x55, sizeof(buf));
 EXPECT_EQ(send(self->fd2, buf, sizeof(buf), 0), sizeof(buf));
 EXPECT_EQ(recv(self->cfd2, buf, sizeof(buf), 0), -1);
 EXPECT_EQ(errno, EMSGSIZE);
 EXPECT_EQ(recv(self->cfd2, buf, sizeof(buf), MSG_DONTWAIT), -1);
 EXPECT_EQ(errno, EAGAIN);
}

TEST_F(tls_err, bad_auth)
{
 char buf[128];
 int n;

 if (self->notls)
  SKIP(return"no TLS support");

 memrnd(buf, sizeof(buf) / 2);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=93 G=94

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge