mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
Merge branch 'tls1.3-key-updates'
Sabrina Dubroca says: ==================== tls: implement key updates for TLS1.3 This adds support for receiving KeyUpdate messages (RFC 8446, 4.6.3 [1]). A sender transmits a KeyUpdate message and then changes its TX key. The receiver should react by updating its RX key before processing the next message. This patchset implements key updates by: 1. pausing decryption when a KeyUpdate message is received, to avoid attempting to use the old key to decrypt a record encrypted with the new key 2. returning -EKEYEXPIRED to syscalls that cannot receive the KeyUpdate message, until the rekey has been performed by userspace 3. passing the KeyUpdate message to userspace as a control message 4. allowing updates of the crypto_info via the TLS_TX/TLS_RX setsockopts This API has been tested with gnutls to make sure that it allows userspace libraries to implement key updates [2]. Thanks to Frantisek Krenzelok <fkrenzel@redhat.com> for providing the implementation in gnutls and testing the kernel patches. ======================================================================= Discussions around v2 of this patchset focused on how HW offload would interact with rekey. RX - The existing SW path will handle all records between the KeyUpdate message signaling the change of key and the new key becoming known to the kernel -- those will be queued encrypted, and decrypted in SW as they are read by userspace (once the key is provided, ie same as this patchset) - Call ->tls_dev_del + ->tls_dev_add immediately during setsockopt(TLS_RX) TX - After setsockopt(TLS_TX), switch to the existing SW path (not the current device_fallback) until we're able to re-enable HW offload - tls_device_sendmsg will call into tls_sw_sendmsg under lock_sock to avoid changing socket ops during the rekey while another thread might be waiting on the lock - We only re-enable HW offload (call ->tls_dev_add to install the new key in HW) once all records sent with the old key have been ACKed. At this point, all unacked records are SW-encrypted with the new key, and the old key is unused by both HW and retransmissions. - If there are no unacked records when userspace does setsockopt(TLS_TX), we can (try to) install the new key in HW immediately. - If yet another key has been provided via setsockopt(TLS_TX), we don't install intermediate keys, only the latest. - TCP notifies ktls of ACKs via the icsk_clean_acked callback. In case of a rekey, tls_icsk_clean_acked will record when all data sent with the most recent past key has been sent. The next call to sendmsg will install the new key in HW. - We close and push the current SW record before reenabling offload. If ->tls_dev_add fails to install the new key in HW, we stay in SW mode. We can add a counter to keep track of this. In addition: Because we can't change socket ops during a rekey, we'll also have to modify do_tls_setsockopt_conf to check ctx->tx_conf and only call either tls_set_device_offload or tls_set_sw_offload. RX already uses the same ops for both TLS_HW and TLS_SW, so we could switch between HW and SW mode on rekey. An alternative would be to have a common sendmsg which locks the socket and then calls the correct implementation. We'll need that anyway for the offload under rekey case, so that would only add a test to the SW path's ops (compared to the current code). That should allow us to simplify build_protos a bit, but might have a performance impact - we'll need to check it if we want to go that route. ======================================================================= Changes since v4: - add counter for received KeyUpdate messages - improve wording in the documentation - improve handling of bogus messages when looking for KeyUpdate's - some coding style clean ups Changes since v3: - rebase on top of net-next - rework tls_check_pending_rekey according to Jakub's feedback - add statistics for rekey: {RX,TX}REKEY{OK,ERROR} - some coding style clean ups ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
da3e3186ef
@ -200,6 +200,32 @@ received without a cmsg buffer set.
|
||||
|
||||
recv will never return data from mixed types of TLS records.
|
||||
|
||||
TLS 1.3 Key Updates
|
||||
-------------------
|
||||
|
||||
In TLS 1.3, KeyUpdate handshake messages signal that the sender is
|
||||
updating its TX key. Any message sent after a KeyUpdate will be
|
||||
encrypted using the new key. The userspace library can pass the new
|
||||
key to the kernel using the TLS_TX and TLS_RX socket options, as for
|
||||
the initial keys. TLS version and cipher cannot be changed.
|
||||
|
||||
To prevent attempting to decrypt incoming records using the wrong key,
|
||||
decryption will be paused when a KeyUpdate message is received by the
|
||||
kernel, until the new key has been provided using the TLS_RX socket
|
||||
option. Any read occurring after the KeyUpdate has been read and
|
||||
before the new key is provided will fail with EKEYEXPIRED. poll() will
|
||||
not report any read events from the socket until the new key is
|
||||
provided. There is no pausing on the transmit side.
|
||||
|
||||
Userspace should make sure that the crypto_info provided has been set
|
||||
properly. In particular, the kernel will not check for key/nonce
|
||||
reuse.
|
||||
|
||||
The number of successful and failed key updates is tracked in the
|
||||
``TlsTxRekeyOk``, ``TlsRxRekeyOk``, ``TlsTxRekeyError``,
|
||||
``TlsRxRekeyError`` statistics. The ``TlsRxRekeyReceived`` statistic
|
||||
counts KeyUpdate handshake messages that have been received.
|
||||
|
||||
Integrating in to userspace TLS library
|
||||
---------------------------------------
|
||||
|
||||
@ -286,3 +312,13 @@ TLS implementation exposes the following per-namespace statistics
|
||||
- ``TlsRxNoPadViolation`` -
|
||||
number of data RX records which had to be re-decrypted due to
|
||||
``TLS_RX_EXPECT_NO_PAD`` mis-prediction.
|
||||
|
||||
- ``TlsTxRekeyOk``, ``TlsRxRekeyOk`` -
|
||||
number of successful rekeys on existing sessions for TX and RX
|
||||
|
||||
- ``TlsTxRekeyError``, ``TlsRxRekeyError`` -
|
||||
number of failed rekeys on existing sessions for TX and RX
|
||||
|
||||
- ``TlsRxRekeyReceived`` -
|
||||
number of received KeyUpdate handshake messages, requiring userspace
|
||||
to provide a new RX key
|
||||
|
@ -59,6 +59,8 @@ struct tls_rec;
|
||||
|
||||
#define TLS_CRYPTO_INFO_READY(info) ((info)->cipher_type)
|
||||
|
||||
#define TLS_HANDSHAKE_KEYUPDATE 24 /* rfc8446 B.3: Key update */
|
||||
|
||||
#define TLS_AAD_SPACE_SIZE 13
|
||||
|
||||
#define TLS_MAX_IV_SIZE 16
|
||||
@ -130,6 +132,7 @@ struct tls_sw_context_rx {
|
||||
u8 async_capable:1;
|
||||
u8 zc_capable:1;
|
||||
u8 reader_contended:1;
|
||||
bool key_update_pending;
|
||||
|
||||
struct tls_strparser strp;
|
||||
|
||||
|
@ -358,6 +358,11 @@ enum
|
||||
LINUX_MIB_TLSRXDEVICERESYNC, /* TlsRxDeviceResync */
|
||||
LINUX_MIB_TLSDECRYPTRETRY, /* TlsDecryptRetry */
|
||||
LINUX_MIB_TLSRXNOPADVIOL, /* TlsRxNoPadViolation */
|
||||
LINUX_MIB_TLSRXREKEYOK, /* TlsRxRekeyOk */
|
||||
LINUX_MIB_TLSRXREKEYERROR, /* TlsRxRekeyError */
|
||||
LINUX_MIB_TLSTXREKEYOK, /* TlsTxRekeyOk */
|
||||
LINUX_MIB_TLSTXREKEYERROR, /* TlsTxRekeyError */
|
||||
LINUX_MIB_TLSRXREKEYRECEIVED, /* TlsRxRekeyReceived */
|
||||
__LINUX_MIB_TLSMAX
|
||||
};
|
||||
|
||||
|
@ -145,7 +145,8 @@ void tls_err_abort(struct sock *sk, int err);
|
||||
int init_prot_info(struct tls_prot_info *prot,
|
||||
const struct tls_crypto_info *crypto_info,
|
||||
const struct tls_cipher_desc *cipher_desc);
|
||||
int tls_set_sw_offload(struct sock *sk, int tx);
|
||||
int tls_set_sw_offload(struct sock *sk, int tx,
|
||||
struct tls_crypto_info *new_crypto_info);
|
||||
void tls_update_rx_zc_capable(struct tls_context *tls_ctx);
|
||||
void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx);
|
||||
void tls_sw_strparser_done(struct tls_context *tls_ctx);
|
||||
|
@ -1227,7 +1227,7 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx)
|
||||
context->resync_nh_reset = 1;
|
||||
|
||||
ctx->priv_ctx_rx = context;
|
||||
rc = tls_set_sw_offload(sk, 0);
|
||||
rc = tls_set_sw_offload(sk, 0, NULL);
|
||||
if (rc)
|
||||
goto release_ctx;
|
||||
|
||||
|
@ -423,9 +423,10 @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
|
||||
ctx = tls_sw_ctx_rx(tls_ctx);
|
||||
psock = sk_psock_get(sk);
|
||||
|
||||
if (skb_queue_empty_lockless(&ctx->rx_list) &&
|
||||
!tls_strp_msg_ready(ctx) &&
|
||||
sk_psock_queue_empty(psock))
|
||||
if ((skb_queue_empty_lockless(&ctx->rx_list) &&
|
||||
!tls_strp_msg_ready(ctx) &&
|
||||
sk_psock_queue_empty(psock)) ||
|
||||
READ_ONCE(ctx->key_update_pending))
|
||||
mask &= ~(EPOLLIN | EPOLLRDNORM);
|
||||
|
||||
if (psock)
|
||||
@ -612,11 +613,13 @@ static int validate_crypto_info(const struct tls_crypto_info *crypto_info,
|
||||
static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
unsigned int optlen, int tx)
|
||||
{
|
||||
struct tls_crypto_info *crypto_info;
|
||||
struct tls_crypto_info *alt_crypto_info;
|
||||
struct tls_crypto_info *crypto_info, *alt_crypto_info;
|
||||
struct tls_crypto_info *old_crypto_info = NULL;
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
const struct tls_cipher_desc *cipher_desc;
|
||||
union tls_crypto_context *crypto_ctx;
|
||||
union tls_crypto_context tmp = {};
|
||||
bool update = false;
|
||||
int rc = 0;
|
||||
int conf;
|
||||
|
||||
@ -633,9 +636,21 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
|
||||
crypto_info = &crypto_ctx->info;
|
||||
|
||||
/* Currently we don't support set crypto info more than one time */
|
||||
if (TLS_CRYPTO_INFO_READY(crypto_info))
|
||||
return -EBUSY;
|
||||
if (TLS_CRYPTO_INFO_READY(crypto_info)) {
|
||||
/* Currently we only support setting crypto info more
|
||||
* than one time for TLS 1.3
|
||||
*/
|
||||
if (crypto_info->version != TLS_1_3_VERSION) {
|
||||
TLS_INC_STATS(sock_net(sk), tx ? LINUX_MIB_TLSTXREKEYERROR
|
||||
: LINUX_MIB_TLSRXREKEYERROR);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
update = true;
|
||||
old_crypto_info = crypto_info;
|
||||
crypto_info = &tmp.info;
|
||||
crypto_ctx = &tmp;
|
||||
}
|
||||
|
||||
rc = copy_from_sockptr(crypto_info, optval, sizeof(*crypto_info));
|
||||
if (rc) {
|
||||
@ -643,7 +658,14 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
goto err_crypto_info;
|
||||
}
|
||||
|
||||
rc = validate_crypto_info(crypto_info, alt_crypto_info);
|
||||
if (update) {
|
||||
/* Ensure that TLS version and ciphers are not modified */
|
||||
if (crypto_info->version != old_crypto_info->version ||
|
||||
crypto_info->cipher_type != old_crypto_info->cipher_type)
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
rc = validate_crypto_info(crypto_info, alt_crypto_info);
|
||||
}
|
||||
if (rc)
|
||||
goto err_crypto_info;
|
||||
|
||||
@ -673,11 +695,17 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSTXDEVICE);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRTXDEVICE);
|
||||
} else {
|
||||
rc = tls_set_sw_offload(sk, 1);
|
||||
rc = tls_set_sw_offload(sk, 1,
|
||||
update ? crypto_info : NULL);
|
||||
if (rc)
|
||||
goto err_crypto_info;
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSTXSW);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRTXSW);
|
||||
|
||||
if (update) {
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSTXREKEYOK);
|
||||
} else {
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSTXSW);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRTXSW);
|
||||
}
|
||||
conf = TLS_SW;
|
||||
}
|
||||
} else {
|
||||
@ -687,14 +715,21 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXDEVICE);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRRXDEVICE);
|
||||
} else {
|
||||
rc = tls_set_sw_offload(sk, 0);
|
||||
rc = tls_set_sw_offload(sk, 0,
|
||||
update ? crypto_info : NULL);
|
||||
if (rc)
|
||||
goto err_crypto_info;
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXSW);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRRXSW);
|
||||
|
||||
if (update) {
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXREKEYOK);
|
||||
} else {
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXSW);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSCURRRXSW);
|
||||
}
|
||||
conf = TLS_SW;
|
||||
}
|
||||
tls_sw_strparser_arm(sk, ctx);
|
||||
if (!update)
|
||||
tls_sw_strparser_arm(sk, ctx);
|
||||
}
|
||||
|
||||
if (tx)
|
||||
@ -713,6 +748,10 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
|
||||
return 0;
|
||||
|
||||
err_crypto_info:
|
||||
if (update) {
|
||||
TLS_INC_STATS(sock_net(sk), tx ? LINUX_MIB_TLSTXREKEYERROR
|
||||
: LINUX_MIB_TLSRXREKEYERROR);
|
||||
}
|
||||
memzero_explicit(crypto_ctx, sizeof(*crypto_ctx));
|
||||
return rc;
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ static const struct snmp_mib tls_mib_list[] = {
|
||||
SNMP_MIB_ITEM("TlsRxDeviceResync", LINUX_MIB_TLSRXDEVICERESYNC),
|
||||
SNMP_MIB_ITEM("TlsDecryptRetry", LINUX_MIB_TLSDECRYPTRETRY),
|
||||
SNMP_MIB_ITEM("TlsRxNoPadViolation", LINUX_MIB_TLSRXNOPADVIOL),
|
||||
SNMP_MIB_ITEM("TlsRxRekeyOk", LINUX_MIB_TLSRXREKEYOK),
|
||||
SNMP_MIB_ITEM("TlsRxRekeyError", LINUX_MIB_TLSRXREKEYERROR),
|
||||
SNMP_MIB_ITEM("TlsTxRekeyOk", LINUX_MIB_TLSTXREKEYOK),
|
||||
SNMP_MIB_ITEM("TlsTxRekeyError", LINUX_MIB_TLSTXREKEYERROR),
|
||||
SNMP_MIB_ITEM("TlsRxRekeyReceived", LINUX_MIB_TLSRXREKEYRECEIVED),
|
||||
SNMP_MIB_SENTINEL
|
||||
};
|
||||
|
||||
|
140
net/tls/tls_sw.c
140
net/tls/tls_sw.c
@ -1314,6 +1314,10 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
|
||||
int ret = 0;
|
||||
long timeo;
|
||||
|
||||
/* a rekey is pending, let userspace deal with it */
|
||||
if (unlikely(ctx->key_update_pending))
|
||||
return -EKEYEXPIRED;
|
||||
|
||||
timeo = sock_rcvtimeo(sk, nonblock);
|
||||
|
||||
while (!tls_strp_msg_ready(ctx)) {
|
||||
@ -1720,6 +1724,36 @@ tls_decrypt_device(struct sock *sk, struct msghdr *msg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tls_check_pending_rekey(struct sock *sk, struct tls_context *ctx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct strp_msg *rxm = strp_msg(skb);
|
||||
const struct tls_msg *tlm = tls_msg(skb);
|
||||
char hs_type;
|
||||
int err;
|
||||
|
||||
if (likely(tlm->control != TLS_RECORD_TYPE_HANDSHAKE))
|
||||
return 0;
|
||||
|
||||
if (rxm->full_len < 1)
|
||||
return 0;
|
||||
|
||||
err = skb_copy_bits(skb, rxm->offset, &hs_type, 1);
|
||||
if (err < 0) {
|
||||
DEBUG_NET_WARN_ON_ONCE(1);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hs_type == TLS_HANDSHAKE_KEYUPDATE) {
|
||||
struct tls_sw_context_rx *rx_ctx = ctx->priv_ctx_rx;
|
||||
|
||||
WRITE_ONCE(rx_ctx->key_update_pending, true);
|
||||
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXREKEYRECEIVED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tls_rx_one_record(struct sock *sk, struct msghdr *msg,
|
||||
struct tls_decrypt_arg *darg)
|
||||
{
|
||||
@ -1739,7 +1773,7 @@ static int tls_rx_one_record(struct sock *sk, struct msghdr *msg,
|
||||
rxm->full_len -= prot->overhead_size;
|
||||
tls_advance_record_sn(sk, prot, &tls_ctx->rx);
|
||||
|
||||
return 0;
|
||||
return tls_check_pending_rekey(sk, tls_ctx, darg->skb);
|
||||
}
|
||||
|
||||
int decrypt_skb(struct sock *sk, struct scatterlist *sgout)
|
||||
@ -2684,12 +2718,22 @@ int init_prot_info(struct tls_prot_info *prot,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tls_set_sw_offload(struct sock *sk, int tx)
|
||||
static void tls_finish_key_update(struct sock *sk, struct tls_context *tls_ctx)
|
||||
{
|
||||
struct tls_sw_context_rx *ctx = tls_ctx->priv_ctx_rx;
|
||||
|
||||
WRITE_ONCE(ctx->key_update_pending, false);
|
||||
/* wake-up pre-existing poll() */
|
||||
ctx->saved_data_ready(sk);
|
||||
}
|
||||
|
||||
int tls_set_sw_offload(struct sock *sk, int tx,
|
||||
struct tls_crypto_info *new_crypto_info)
|
||||
{
|
||||
struct tls_crypto_info *crypto_info, *src_crypto_info;
|
||||
struct tls_sw_context_tx *sw_ctx_tx = NULL;
|
||||
struct tls_sw_context_rx *sw_ctx_rx = NULL;
|
||||
const struct tls_cipher_desc *cipher_desc;
|
||||
struct tls_crypto_info *crypto_info;
|
||||
char *iv, *rec_seq, *key, *salt;
|
||||
struct cipher_context *cctx;
|
||||
struct tls_prot_info *prot;
|
||||
@ -2701,44 +2745,47 @@ int tls_set_sw_offload(struct sock *sk, int tx)
|
||||
ctx = tls_get_ctx(sk);
|
||||
prot = &ctx->prot_info;
|
||||
|
||||
if (tx) {
|
||||
ctx->priv_ctx_tx = init_ctx_tx(ctx, sk);
|
||||
if (!ctx->priv_ctx_tx)
|
||||
return -ENOMEM;
|
||||
/* new_crypto_info != NULL means rekey */
|
||||
if (!new_crypto_info) {
|
||||
if (tx) {
|
||||
ctx->priv_ctx_tx = init_ctx_tx(ctx, sk);
|
||||
if (!ctx->priv_ctx_tx)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
ctx->priv_ctx_rx = init_ctx_rx(ctx);
|
||||
if (!ctx->priv_ctx_rx)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) {
|
||||
sw_ctx_tx = ctx->priv_ctx_tx;
|
||||
crypto_info = &ctx->crypto_send.info;
|
||||
cctx = &ctx->tx;
|
||||
aead = &sw_ctx_tx->aead_send;
|
||||
} else {
|
||||
ctx->priv_ctx_rx = init_ctx_rx(ctx);
|
||||
if (!ctx->priv_ctx_rx)
|
||||
return -ENOMEM;
|
||||
|
||||
sw_ctx_rx = ctx->priv_ctx_rx;
|
||||
crypto_info = &ctx->crypto_recv.info;
|
||||
cctx = &ctx->rx;
|
||||
aead = &sw_ctx_rx->aead_recv;
|
||||
}
|
||||
|
||||
cipher_desc = get_cipher_desc(crypto_info->cipher_type);
|
||||
src_crypto_info = new_crypto_info ?: crypto_info;
|
||||
|
||||
cipher_desc = get_cipher_desc(src_crypto_info->cipher_type);
|
||||
if (!cipher_desc) {
|
||||
rc = -EINVAL;
|
||||
goto free_priv;
|
||||
}
|
||||
|
||||
rc = init_prot_info(prot, crypto_info, cipher_desc);
|
||||
rc = init_prot_info(prot, src_crypto_info, cipher_desc);
|
||||
if (rc)
|
||||
goto free_priv;
|
||||
|
||||
iv = crypto_info_iv(crypto_info, cipher_desc);
|
||||
key = crypto_info_key(crypto_info, cipher_desc);
|
||||
salt = crypto_info_salt(crypto_info, cipher_desc);
|
||||
rec_seq = crypto_info_rec_seq(crypto_info, cipher_desc);
|
||||
|
||||
memcpy(cctx->iv, salt, cipher_desc->salt);
|
||||
memcpy(cctx->iv + cipher_desc->salt, iv, cipher_desc->iv);
|
||||
memcpy(cctx->rec_seq, rec_seq, cipher_desc->rec_seq);
|
||||
iv = crypto_info_iv(src_crypto_info, cipher_desc);
|
||||
key = crypto_info_key(src_crypto_info, cipher_desc);
|
||||
salt = crypto_info_salt(src_crypto_info, cipher_desc);
|
||||
rec_seq = crypto_info_rec_seq(src_crypto_info, cipher_desc);
|
||||
|
||||
if (!*aead) {
|
||||
*aead = crypto_alloc_aead(cipher_desc->cipher_name, 0, 0);
|
||||
@ -2751,20 +2798,30 @@ int tls_set_sw_offload(struct sock *sk, int tx)
|
||||
|
||||
ctx->push_pending_record = tls_sw_push_pending_record;
|
||||
|
||||
/* setkey is the last operation that could fail during a
|
||||
* rekey. if it succeeds, we can start modifying the
|
||||
* context.
|
||||
*/
|
||||
rc = crypto_aead_setkey(*aead, key, cipher_desc->key);
|
||||
if (rc)
|
||||
goto free_aead;
|
||||
if (rc) {
|
||||
if (new_crypto_info)
|
||||
goto out;
|
||||
else
|
||||
goto free_aead;
|
||||
}
|
||||
|
||||
rc = crypto_aead_setauthsize(*aead, prot->tag_size);
|
||||
if (rc)
|
||||
goto free_aead;
|
||||
if (!new_crypto_info) {
|
||||
rc = crypto_aead_setauthsize(*aead, prot->tag_size);
|
||||
if (rc)
|
||||
goto free_aead;
|
||||
}
|
||||
|
||||
if (sw_ctx_rx) {
|
||||
if (!tx && !new_crypto_info) {
|
||||
tfm = crypto_aead_tfm(sw_ctx_rx->aead_recv);
|
||||
|
||||
tls_update_rx_zc_capable(ctx);
|
||||
sw_ctx_rx->async_capable =
|
||||
crypto_info->version != TLS_1_3_VERSION &&
|
||||
src_crypto_info->version != TLS_1_3_VERSION &&
|
||||
!!(tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC);
|
||||
|
||||
rc = tls_strp_init(&sw_ctx_rx->strp, sk);
|
||||
@ -2772,18 +2829,33 @@ int tls_set_sw_offload(struct sock *sk, int tx)
|
||||
goto free_aead;
|
||||
}
|
||||
|
||||
memcpy(cctx->iv, salt, cipher_desc->salt);
|
||||
memcpy(cctx->iv + cipher_desc->salt, iv, cipher_desc->iv);
|
||||
memcpy(cctx->rec_seq, rec_seq, cipher_desc->rec_seq);
|
||||
|
||||
if (new_crypto_info) {
|
||||
unsafe_memcpy(crypto_info, new_crypto_info,
|
||||
cipher_desc->crypto_info,
|
||||
/* size was checked in do_tls_setsockopt_conf */);
|
||||
memzero_explicit(new_crypto_info, cipher_desc->crypto_info);
|
||||
if (!tx)
|
||||
tls_finish_key_update(sk, ctx);
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
free_aead:
|
||||
crypto_free_aead(*aead);
|
||||
*aead = NULL;
|
||||
free_priv:
|
||||
if (tx) {
|
||||
kfree(ctx->priv_ctx_tx);
|
||||
ctx->priv_ctx_tx = NULL;
|
||||
} else {
|
||||
kfree(ctx->priv_ctx_rx);
|
||||
ctx->priv_ctx_rx = NULL;
|
||||
if (!new_crypto_info) {
|
||||
if (tx) {
|
||||
kfree(ctx->priv_ctx_tx);
|
||||
ctx->priv_ctx_tx = NULL;
|
||||
} else {
|
||||
kfree(ctx->priv_ctx_rx);
|
||||
ctx->priv_ctx_rx = NULL;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
|
@ -44,9 +44,11 @@ struct tls_crypto_info_keys {
|
||||
};
|
||||
|
||||
static void tls_crypto_info_init(uint16_t tls_version, uint16_t cipher_type,
|
||||
struct tls_crypto_info_keys *tls12)
|
||||
struct tls_crypto_info_keys *tls12,
|
||||
char key_generation)
|
||||
{
|
||||
memset(tls12, 0, sizeof(*tls12));
|
||||
memset(tls12, key_generation, sizeof(*tls12));
|
||||
memset(tls12, 0, sizeof(struct tls_crypto_info));
|
||||
|
||||
switch (cipher_type) {
|
||||
case TLS_CIPHER_CHACHA20_POLY1305:
|
||||
@ -275,7 +277,7 @@ TEST_F(tls_basic, recseq_wrap)
|
||||
if (self->notls)
|
||||
SKIP(return, "no TLS support");
|
||||
|
||||
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_128, &tls12);
|
||||
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);
|
||||
@ -391,7 +393,7 @@ FIXTURE_SETUP(tls)
|
||||
SKIP(return, "Unsupported cipher in FIPS mode");
|
||||
|
||||
tls_crypto_info_init(variant->tls_version, variant->cipher_type,
|
||||
&tls12);
|
||||
&tls12, 0);
|
||||
|
||||
ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
|
||||
|
||||
@ -1175,7 +1177,7 @@ TEST_F(tls, bidir)
|
||||
struct tls_crypto_info_keys tls12;
|
||||
|
||||
tls_crypto_info_init(variant->tls_version, variant->cipher_type,
|
||||
&tls12);
|
||||
&tls12, 0);
|
||||
|
||||
ret = setsockopt(self->fd, SOL_TLS, TLS_RX, &tls12,
|
||||
tls12.len);
|
||||
@ -1614,7 +1616,7 @@ TEST_F(tls, getsockopt)
|
||||
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);
|
||||
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);
|
||||
@ -1668,6 +1670,464 @@ TEST_F(tls, recv_efault)
|
||||
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, 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));
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE(tls_err)
|
||||
{
|
||||
int fd, cfd;
|
||||
@ -1696,7 +2156,7 @@ FIXTURE_SETUP(tls_err)
|
||||
int ret;
|
||||
|
||||
tls_crypto_info_init(variant->tls_version, TLS_CIPHER_AES_GCM_128,
|
||||
&tls12);
|
||||
&tls12, 0);
|
||||
|
||||
ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
|
||||
ulp_sock_pair(_metadata, &self->fd2, &self->cfd2, &self->notls);
|
||||
@ -2118,7 +2578,7 @@ TEST(tls_v6ops) {
|
||||
int sfd, ret, fd;
|
||||
socklen_t len, len2;
|
||||
|
||||
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_128, &tls12);
|
||||
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_128, &tls12, 0);
|
||||
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_addr = in6addr_any;
|
||||
@ -2177,7 +2637,7 @@ TEST(prequeue) {
|
||||
len = sizeof(addr);
|
||||
memrnd(buf, sizeof(buf));
|
||||
|
||||
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_256, &tls12);
|
||||
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_GCM_256, &tls12, 0);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
Loading…
Reference in New Issue
Block a user