In the current source, incoming ESP sequence numbers (vpninfo->esp_in[vpinfo->current_esp_in].seq) are not actually tracked at all unless replay protection is in use. At the time of a rekey, old_esp_maxseq is *set based on the current value of the incoming seq* at the time of the switchover: if (new_keys) { vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32; And then esp.c rejects packets with the old incoming SPI, unless seqp < old_esp_maxseq: } else if (pkt->esp.spi == old_esp->spi && ntohl(pkt->esp.seq) + esp->seq < vpninfo->old_esp_maxseq) { vpn_progress(vpninfo, PRG_TRACE, _("Consider SPI 0x%x, seq %u against outgoing ESP setup\n"), (unsigned)ntohl(old_esp->spi), (unsigned)ntohl(pkt->esp.seq)); if (decrypt_esp_packet(vpninfo, old_esp, pkt)) continue; This code is supposed to allow a smooth handover from the old incoming SPI to the new one after a rekey, so that in-flight packets from the old SPI aren't totally dropped, but also aren't allowed to continue forever. This patch tracks the latest sequence number even if ESP replay protection isn't in use -- however inadvisable that may be -- allowing the handover to work correctly. This patch also improves the confusing trace message shown when a packet from the old SPI is received. Signed-off-by: Daniel Lenski <dlenski at gmail.com> --- esp.c | 2 +- gnutls-esp.c | 2 ++ openssl-esp.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/esp.c b/esp.c index 7876fd5..1b4b227 100644 --- a/esp.c +++ b/esp.c @@ -299,7 +299,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout) } else if (pkt->esp.spi == old_esp->spi && ntohl(pkt->esp.seq) + esp->seq < vpninfo->old_esp_maxseq) { vpn_progress(vpninfo, PRG_TRACE, - _("Consider SPI 0x%x, seq %u against outgoing ESP setup\n"), + _("Received ESP packet from old SPI 0x%x, seq %u\n"), (unsigned)ntohl(old_esp->spi), (unsigned)ntohl(pkt->esp.seq)); if (decrypt_esp_packet(vpninfo, old_esp, pkt)) continue; diff --git a/gnutls-esp.c b/gnutls-esp.c index 916cbc7..24d6620 100644 --- a/gnutls-esp.c +++ b/gnutls-esp.c @@ -166,6 +166,8 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct if (vpninfo->esp_replay_protect && verify_packet_seqno(vpninfo, esp, ntohl(pkt->esp.seq))) return -EINVAL; + else + esp->seq = ntohl(pkt->esp.seq) + 1; gnutls_cipher_set_iv(esp->cipher, pkt->esp.iv, sizeof(pkt->esp.iv)); diff --git a/openssl-esp.c b/openssl-esp.c index c3dff51..8af838b 100644 --- a/openssl-esp.c +++ b/openssl-esp.c @@ -204,7 +204,8 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct if (vpninfo->esp_replay_protect && verify_packet_seqno(vpninfo, esp, ntohl(pkt->esp.seq))) return -EINVAL; - + else + esp->seq = ntohl(pkt->esp.seq) + 1; if (!EVP_DecryptInit_ex(esp->cipher, NULL, NULL, NULL, pkt->esp.iv)) { -- 2.7.4