From: Ralf Lici Date: Tue, 21 Jul 2026 20:38:01 +0000 (+0200) Subject: dco: make key state desync recoverable X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ea3bb67e2b1e130c90cd2b28ec5e31a455d60164;p=thirdparty%2Fopenvpn.git dco: make key state desync recoverable If installing a DCO key succeeds, always record the slot in the corresponding key_state. The installed-key counter only tracks whether the number of kernel slots grew, but a successful KEY_NEW still means that this key_state is associated with the selected DCO slot. Also replace DCO key-state assertions in dco_update_keys() with error returns. This preserves the invariant checks but lets the existing caller restart the connection instead of aborting the process if userspace ever detects inconsistent DCO key state. Github: OpenVPN/openvpn-private-issues#143 Reported-By: Hcamael Reported-By: 章鱼哥 (www.aipyaipy.com) Change-Id: I4d0887839b4a13a92e92250d1b315dec949698f3 Signed-off-by: Ralf Lici Acked-by: Antonio Quartulli Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1795 Message-Id: <20260721203807.5813-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37732.html Signed-off-by: Gert Doering --- diff --git a/src/openvpn/dco.c b/src/openvpn/dco.c index e944547b9..25843688d 100644 --- a/src/openvpn/dco.c +++ b/src/openvpn/dco.c @@ -73,9 +73,12 @@ dco_install_key(struct tls_multi *multi, struct key_state *ks, const uint8_t *en int ret = dco_new_key(multi->dco, multi->dco_peer_id, ks->key_id, slot, encrypt_key, encrypt_iv, decrypt_key, decrypt_iv, ciphername, epoch); - if ((ret == 0) && (multi->dco_keys_installed < 2)) + if (ret == 0) { - multi->dco_keys_installed++; + if (multi->dco_keys_installed < 2) + { + multi->dco_keys_installed++; + } ks->dco_status = (slot == OVPN_KEY_SLOT_PRIMARY) ? DCO_INSTALLED_PRIMARY : DCO_INSTALLED_SECONDARY; } @@ -166,7 +169,13 @@ dco_update_keys(dco_context_t *dco, struct tls_multi *multi) /* if we have a primary key, it must have been installed already (keys * are installed upon generation in the TLS code) */ - ASSERT(primary->dco_status != DCO_NOT_INSTALLED); + if (primary->dco_status == DCO_NOT_INSTALLED) + { + msg(D_DCO, "DCO key state mismatch: selected primary key is not installed " + "(peer_id=%d, key_id=%d, dco_keys_installed=%d)", + multi->dco_peer_id, primary->key_id, multi->dco_keys_installed); + return false; + } struct key_state *secondary = dco_get_secondary_key(multi, primary); /* if the current primary key was installed as secondary in DCO, @@ -190,6 +199,14 @@ dco_update_keys(dco_context_t *dco, struct tls_multi *multi) primary->key_id); } + if (secondary && secondary->dco_status != DCO_INSTALLED_PRIMARY) + { + msg(D_DCO, "DCO key state mismatch: expected old primary key is not installed as DCO primary before swap " + "(peer_id=%d, new_primary_key_id=%d, old_primary_key_id=%d, old_primary_dco_status=%d, dco_keys_installed=%d)", + multi->dco_peer_id, primary->key_id, secondary->key_id, secondary->dco_status, multi->dco_keys_installed); + return false; + } + int ret = dco_swap_keys(dco, multi->dco_peer_id); if (ret < 0) { @@ -200,7 +217,6 @@ dco_update_keys(dco_context_t *dco, struct tls_multi *multi) primary->dco_status = DCO_INSTALLED_PRIMARY; if (secondary) { - ASSERT(secondary->dco_status == DCO_INSTALLED_PRIMARY); secondary->dco_status = DCO_INSTALLED_SECONDARY; } }