diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 8f34eaab131..d548c8d4360 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -94,12 +94,16 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work, goto err; } - /* Remainder of IV consists of implicit part (unique per session) */ - ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); - ASSERT(iv_buffer.len == iv_len); + /* Write packet id part of IV to work buffer */ + ASSERT(buf_write(&work, iv, packet_id_size(false))); + + /* This generates the IV by XORing the implicit part of the IV + * with the packet id already written to the iv buffer */ + for (int i = 0; i < iv_len; i++) + { + iv[i] = iv[i] ^ ctx->implicit_iv[i]; + } - /* Write explicit part of IV to work buffer */ - ASSERT(buf_write(&work, iv, iv_len - ctx->implicit_iv_len)); dmsg(D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex(iv, iv_len, 0, &gc)); /* Init cipher_ctx with IV. key & keylen are already initialized */ @@ -390,16 +394,21 @@ openvpn_decrypt_aead(struct buffer *buf, struct buffer work, { uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 }; const int iv_len = cipher_ctx_iv_length(ctx->cipher); - const size_t packet_iv_len = iv_len - ctx->implicit_iv_len; + const size_t packet_iv_len = packet_id_size(false); - ASSERT(ctx->implicit_iv_len <= iv_len); - if (buf->len + ctx->implicit_iv_len < iv_len) + if (buf->len < packet_iv_len) { CRYPT_ERROR("missing IV info"); } memcpy(iv, BPTR(buf), packet_iv_len); - memcpy(iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len); + + /* This generates the IV by XORing the implicit part of the IV + * with the packet id already written to the iv buffer */ + for (int i = 0; i < iv_len; i++) + { + iv[i] = iv[i] ^ ctx->implicit_iv[i]; + } dmsg(D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex(iv, iv_len, 0, &gc)); @@ -920,7 +929,6 @@ free_key_ctx(struct key_ctx *ctx) hmac_ctx_free(ctx->hmac); ctx->hmac = NULL; } - ctx->implicit_iv_len = 0; } void @@ -1036,18 +1044,15 @@ test_crypto(struct crypto_options *co, struct frame *frame) cipher_ctx_t *cipher = co->key_ctx_bi.encrypt.cipher; if (cipher_ctx_mode_aead(cipher)) { - size_t impl_iv_len = cipher_ctx_iv_length(cipher) - sizeof(packet_id_type); ASSERT(cipher_ctx_iv_length(cipher) <= OPENVPN_MAX_IV_LENGTH); ASSERT(cipher_ctx_iv_length(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); /* Generate dummy implicit IV */ ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH)); - co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; memcpy(co->key_ctx_bi.decrypt.implicit_iv, co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); - co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; } } diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 074dad68f73..04d7bb2ad08 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -163,6 +163,17 @@ struct key_ctx { cipher_ctx_t *cipher; /**< Generic cipher %context. */ hmac_ctx_t *hmac; /**< Generic HMAC %context. */ + /** + * This implicit IV will be always XORed with the packet id that is sent on + * the wire to get the IV. For the common AEAD ciphers of AES-GCM and + * Chacha20-Poly1305, the length of the IV is 12 bytes (96 bits). + * + * For non-epoch 32bit packet id AEAD format we set the first 32 + * bits of implicit_iv to 0. + * Xor with the packet id in this case works as concatenation: + * after xor the lower 32 bit of the IV are the packet id and + * the rest of the IV is from the implicit IV. + */ uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH]; /**< The implicit part of the IV */ size_t implicit_iv_len; /**< The length of implicit_iv */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 33c22b48373..fcfb3449f19 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1542,10 +1542,11 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) size_t impl_iv_len = 0; ASSERT(cipher_ctx_iv_length(ctx->cipher) >= OPENVPN_AEAD_MIN_IV_LEN); impl_iv_len = cipher_ctx_iv_length(ctx->cipher) - sizeof(packet_id_type); - ASSERT(impl_iv_len <= OPENVPN_MAX_IV_LENGTH); + ASSERT(impl_iv_len + sizeof(packet_id_type) <= OPENVPN_MAX_IV_LENGTH); ASSERT(impl_iv_len <= key_len); - memcpy(ctx->implicit_iv, key, impl_iv_len); - ctx->implicit_iv_len = impl_iv_len; + CLEAR(ctx->implicit_iv); + /* The first bytes of the IV are filled with the packet id */ + memcpy(ctx->implicit_iv + sizeof(packet_id_type), key, impl_iv_len); } } diff --git a/tests/unit_tests/openvpn/test_ssl.c b/tests/unit_tests/openvpn/test_ssl.c index a1ca3443740..ae33cc6eb03 100644 --- a/tests/unit_tests/openvpn/test_ssl.c +++ b/tests/unit_tests/openvpn/test_ssl.c @@ -284,18 +284,15 @@ init_implicit_iv(struct crypto_options *co) if (cipher_ctx_mode_aead(cipher)) { - size_t impl_iv_len = cipher_ctx_iv_length(cipher) - sizeof(packet_id_type); ASSERT(cipher_ctx_iv_length(cipher) <= OPENVPN_MAX_IV_LENGTH); ASSERT(cipher_ctx_iv_length(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); /* Generate dummy implicit IV */ ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH)); - co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; memcpy(co->key_ctx_bi.decrypt.implicit_iv, co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); - co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; } }