Skip to content

feat(openvpn): TLS rekey fix, data-ciphers negotiation, tls-crypt-v2 - #2989

Merged
wwqgtxx merged 5 commits into
MetaCubeX:Alphafrom
Lanlan13-14:Alpha
Jul 18, 2026
Merged

feat(openvpn): TLS rekey fix, data-ciphers negotiation, tls-crypt-v2#2989
wwqgtxx merged 5 commits into
MetaCubeX:Alphafrom
Lanlan13-14:Alpha

Conversation

@Lanlan13-14

@Lanlan13-14 Lanlan13-14 commented Jul 18, 2026

Copy link
Copy Markdown

Three fixes for the OpenVPN client:

  1. TLS rekey: the previous code closed the connection when receiving a soft reset from the server instead of renegotiating. This caused connections to drop on every rekey cycle (default 1h). The client now performs TLS renegotiation, re-exchanges key material, and swaps the data channel atomically.

  2. data-ciphers negotiation: the client now advertises an IV_CIPHERS list and negotiates the data cipher from the server's pushed cipher list. Supports data-ciphers-fallback for servers without negotiation.

  3. tls-crypt-v2: implements the V3/WKC handshake using a client PEM containing 256 bytes of key material plus a wrapped client key, sent with P_CONTROL_HARD_RESET_CLIENT_V3.

Tested against a real OpenVPN server. 61 unit tests pass.

Three core fixes for the OpenVPN client:

1. TLS rekey renegotiation (critical): Fixed fatal bug where
   watchControl() terminated the connection on soft reset instead of
   performing TLS renegotiation. OpenVPN servers rekey every ~1h by
   default, causing all connections to die after that period.
   - control.go: SendSoftReset (toggles keyID, resets counters)
   - control.go: classifyWatchPacketLocked accepts alternating keyIDs
   - client.go: doKeyExchange extracted for reuse in rekey
   - client.go: dataLock (RWMutex) for atomic DataChannel swap
   - client.go: tls.Config RenegotiateFreelyAsClient

2. data-ciphers negotiation + fallback: Client advertises IV_CIPHERS
   list, negotiates cipher from server-pushed list intersection.
   - config.go: DataCiphers + FallbackCipher + NegotiateCipher()
   - keymethod.go: InstallScriptPeerInfo sends IV_CIPHERS list
   - push.go: Parse data-ciphers/ncp-ciphers/cipher push options
   - client.go: doKeyExchange negotiates cipher, derives at max length

3. tls-crypt-v2: Real OpenVPN V3/WKC protocol.
   - tlscrypt_v2.go: Single client PEM (256B key + wrapped key)
   - control.go: V3 opcode + wrapped key appended to initial packet
   - config.go: TLSCryptV2 field + PEM decoding + mutual exclusion

Tests: 61/61 pass
…rence during rekey

ReadIPPacket previously grabbed c.data before calling ReadDataPacket,
which can block for a long time. If a rekey swapped c.data during that
window, the packet would be decrypted with a stale DataChannel and
silently dropped.
@wwqgtxx
wwqgtxx merged commit e26714a into MetaCubeX:Alpha Jul 18, 2026
135 checks passed
kuno pushed a commit to kuno/mihomo that referenced this pull request Aug 12, 2026
@wwqgtxx

wwqgtxx commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

It looks like this PR of yours has caused a new regression:
#3085

@Lanlan13-14

Lanlan13-14 commented Aug 13, 2026 via email

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants