@@ -365,9 +365,104 @@
assert_memory_equal(BPTR(&src), BPTR(&buf), i);
}
+
+
gc_free(&gc);
}
+static void
+encrypt_one_packet(struct crypto_options *co, int len)
+{
+ struct frame frame;
+ init_frame_parameters(&frame);
+
+ struct gc_arena gc = gc_new();
+ struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
+ struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
+ struct buffer work = alloc_buf_gc(BUF_SIZE(&frame), &gc);
+ struct buffer buf = clear_buf();
+ struct buffer src = alloc_buf_gc(frame.buf.payload_size, &gc);
+ void *buf_p;
+
+ ASSERT(buf_init(&work, frame.buf.headroom));
+
+ /*
+ * Load src with random data.
+ */
+ ASSERT(buf_init(&src, 0));
+ ASSERT(len <= src.capacity);
+ src.len = len;
+ ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
+
+ /* copy source to input buf */
+ buf = work;
+ buf_p = buf_write_alloc(&buf, BLEN(&src));
+ ASSERT(buf_p);
+ memcpy(buf_p, BPTR(&src), BLEN(&src));
+
+ ASSERT(buf_init(&encrypt_workspace, frame.buf.headroom)); \
+ openvpn_encrypt(&buf, encrypt_workspace, co);
+
+ /* decrypt */
+ openvpn_decrypt(&buf, decrypt_workspace, co, &frame, BPTR(&buf));
+
+ /* compare */
+ assert_int_equal(buf.len, src.len);
+ assert_memory_equal(BPTR(&src), BPTR(&buf), len);
+
+ gc_free(&gc);
+}
+
+
+static void
+check_aead_limits(struct crypto_options *co, bool chachapoly)
+{
+
+ /* Check that we correctly react when we have a nearing AEAD limits */
+
+ /* manually increase the send counter to be past
+ * the GCM usage limit */
+ co->key_ctx_bi.encrypt.plaintext_blocks = 1ul << 40;
+
+
+ bool epoch = (co->flags & CO_EPOCH_DATA_KEY_FORMAT);
+
+ int expected_epoch = epoch ? 4 : 0;
+
+ /* Ensure that we are still on the initial key (unit test uses 4)
+ * or that it is 0 when epoch is not in use */
+ assert_int_equal(co->key_ctx_bi.encrypt.epoch, expected_epoch);
+
+ encrypt_one_packet(co, 1000);
+
+ /* either epoch key has been updated or warning is enabled */
+ if (epoch && !chachapoly)
+ {
+ expected_epoch++;
+ }
+
+ assert_int_equal(co->key_ctx_bi.encrypt.epoch, expected_epoch);
+
+ if (!epoch)
+ {
+ /* Check always against the GCM usage limit here to see if that
+ * check works */
+ assert_true(aead_usage_limit_reached((1ull << 36),
+ &co->key_ctx_bi.encrypt,
+ co->packet_id.send.id));
+ return;
+ }
+
+ /* Move to the end of the epoch data key send PID range, ChachaPoly
+ * should now also move to a new epoch data key */
+ co->packet_id.send.id = PACKET_ID_EPOCH_MAX;
+
+ encrypt_one_packet(co, 1000);
+ encrypt_one_packet(co, 1000);
+
+ expected_epoch++;
+ assert_int_equal(co->key_ctx_bi.encrypt.epoch, expected_epoch);
+}
struct crypto_options
@@ -428,16 +523,21 @@
static void
run_data_channel_with_cipher_epoch(const char *cipher)
{
+ bool ischacha = !strcmp(cipher, "ChaCha20-Poly1305");
+
struct crypto_options co = init_crypto_options(cipher, "none", true, NULL);
do_data_channel_round_trip(&co);
+ check_aead_limits(&co, ischacha);
uninit_crypto_options(&co);
}
static void
run_data_channel_with_cipher(const char *cipher, const char *auth)
{
+ bool ischacha = !strcmp(cipher, "ChaCha20-Poly1305");
struct crypto_options co = init_crypto_options(cipher, auth, false, NULL);
do_data_channel_round_trip(&co);
+ check_aead_limits(&co, ischacha);
uninit_crypto_options(&co);
}