Page MenuHomeVyOS Platform

Not all crypto and integrity algorithms work in VPP IPsec
Needs testing, HighPublicBUG

Description

According to the original README from the Marvell repository, AES-GCM and AES-CBC are tested and should be supported by the linux-cp plugin and VPP. However, our testing shows that only AES-CBC actually works.

There is a chance that during migration to 25.06, something was lost or we are missing something.

An example of the configuration that is expected to be correct:

set interfaces ethernet eth1 address '192.168.99.1/24'
set interfaces ethernet eth2 address '192.168.102.1/24'
set interfaces vti vti1
set protocols static route 192.168.202.0/24 interface vti1
set system option kernel memory hugepage-size 2M hugepage-count '1024'
set vpn ipsec authentication psk psk1 id 'A'
set vpn ipsec authentication psk psk1 id 'B'
set vpn ipsec authentication psk psk1 secret 'AB'
set vpn ipsec esp-group esp1 mode 'tunnel'
set vpn ipsec esp-group esp1 pfs 'disable'

###
set vpn ipsec esp-group esp1 proposal 10 encryption 'aes256gcm128'
###

set vpn ipsec esp-group esp1 proposal 10 hash 'sha256'
set vpn ipsec ike-group ike1 close-action 'none'
set vpn ipsec ike-group ike1 dead-peer-detection action 'clear'
set vpn ipsec ike-group ike1 proposal 10 encryption 'camellia256ccm96'
set vpn ipsec ike-group ike1 proposal 10 hash 'sha256'
set vpn ipsec interface 'eth1'
set vpn ipsec site-to-site peer B authentication local-id 'A'
set vpn ipsec site-to-site peer B authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer B authentication remote-id 'B'
set vpn ipsec site-to-site peer B connection-type 'none'
set vpn ipsec site-to-site peer B default-esp-group 'esp1'
set vpn ipsec site-to-site peer B ike-group 'ike1'
set vpn ipsec site-to-site peer B local-address '192.168.99.1'
set vpn ipsec site-to-site peer B remote-address '192.168.99.3'
set vpn ipsec site-to-site peer B vti bind 'vti1'
set vpn ipsec site-to-site peer B vti traffic-selector remote prefix '192.168.202.0/24'
set vpp settings buffers buffers-per-numa '1024'
set vpp settings buffers data-size '1700'
set vpp settings buffers page-size '2M'
set vpp settings interface eth1 driver 'dpdk'
set vpp settings interface eth2 driver 'dpdk'
set vpp settings ipsec netlink rx-buffer-size '32000'
set vpp settings lcp ignore-kernel-routes
set vpp settings memory default-hugepage-size '2M'
set vpp settings memory main-heap-page-size '2M'
set vpp settings memory main-heap-size '1G'
set vpp settings statseg page-size '2M'
set vpp settings statseg size '128M'
set vpp settings unix poll-sleep-usec '500'

This config leads to the error when VPP tries to install SA from the kernel:

Sep 02 14:36:30 vyos vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 14:36:30 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 14:36:30 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 14:36:30 vyos vpp[1777]: linux-cp/ipsec: crypto param extraction failed

The same config with aes256 (CBC variant) works fine.

Examples of other algorithms:

aes256ccm128:

Sep 02 15:03:11 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 15:03:11 vyos vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 15:03:11 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: crypto param extraction failed
Sep 02 15:03:11 vyos vpp[1777]: linux-cp/ipsec: crypto param extraction failed
aes256ctr:

Sep 02 15:03:50 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: Invalid/Unsupported crypto algo: rfc3686(ctr(aes)) keylen: 288
Sep 02 15:03:50 vyos vpp[1777]: linux-cp/ipsec: Invalid/Unsupported crypto algo: rfc3686(ctr(aes)) keylen: 288
Sep 02 15:03:50 vyos vpp[1777]: vpp[1777]: linux-cp/ipsec: Invalid/Unsupported crypto algo: rfc3686(ctr(aes)) keylen: 288
Sep 02 15:03:50 vyos vpp[1777]: linux-cp/ipsec: Invalid/Unsupported crypto algo: rfc3686(ctr(aes)) keylen: 288

And so on. All other algorithms except AES-CBC lead to crypto param extraction failed or Invalid/Unsupported crypto algo.

It was tested with:

  • Null encryption
  • AES-CTR
  • AES-CCM with ICV
  • AES-GCM with ICV
  • Null encryption with AES-GMAC
  • 3DES-EDE-CBC
  • Blowfish-CBC
  • Camellia-CBC
  • Camellia-COUNTER
  • Camellia-CCM with ICV
  • Serpent-CBC
  • Twofish-CBC
  • CAST-CBC
  • ChaCha20/Poly1305 with ICV

The similar sroty is with unsupported integrity algorithms, with a difference that if an algorithm is unsupported, there are no messages at all in logs.

Supported algorithms are:

  • MD5 HMAC
  • SHA1 HMAC
  • SHA2_256_128 HMAC
  • SHA2_384_192 HMAC
  • SHA2_512_256 HMAC

Not Supported:

  • MD5_128 HMAC
  • SHA1_160 HMAC
  • SHA2_256_96 HMAC
  • AES XCBC
  • AES CMAC
  • AES-GMAC

What we need to do

  1. Check why AES-GCM does not work, and fix this if possible.
  2. Check how hard it would be to add support for more algorithms: crypto engines can cover a lot (check show crypto handlers output in vppctl).

Details

Version
2025.09.01-0023-rolling
Is it a breaking change?
Unspecified (possibly destroys the router)
Issue type
Bug (incorrect behavior)

Related Objects

StatusSubtypeAssignedTask
OpenBUGNone
Needs testingBUGRC

Event Timeline

set vpn ipsec esp-group esp1 proposal 10 encryption aes256gcm128

no errors in vpp log, but packets dropped with ‘ESP decryption failed’

vpp trace:

00:06:11:885972: ip4-receive
    fib:0 adj:14 flow:0x00000000
  IPSEC_ESP: 192.168.2.3 -> 192.168.2.1
    tos 0x00, ttl 64, length 140, checksum 0xb4eb dscp CS0 ecn NON_ECN
    fragment id 0x0000, flags DONT_FRAGMENT
00:06:11:885975: ipsec4-tun-input
  IPSec: remote:192.168.2.3 spi:3238175729 (0xc102a3f1) sa:0 tun:0 seq 35
00:06:11:885976: esp4-decrypt-tun
  esp: crypto aes-gcm-128 integrity none pkt-seq 35 sa-seq 0 pkt-seq-hi 0
00:06:11:885983: ip4-drop
    fib:0 adj:18 flow:0x00000000
  ICMP: 203.225.235.178 -> 87.246.41.232
    version 12, header length 4
    tos 0x02, ttl 23, length 41969, checksum 0x22b0 (should be 0x4a74) dscp CS0 ecn ECT_1
    fragment id 0x0000 offset 280
00:06:11:885984: error-drop
  rx:ipsec1
00:06:11:885986: drop
  esp4-decrypt-tun: ESP decryption failed

Encryption/decryption failures for AES-GCM don't reproduce anymore, tested the following variants:

256 bit AES-GCM with 128 bit ICV ( aes-gcm-256 )
192 bit AES-GCM with 128 bit ICV ( aes-gcm-192 )
128 bit AES-GCM with 128 bit ICV ( aes-gcm-128 )

set vpn ipsec esp-group ESP-group proposal 1 encryption 'aes256gcm128'
set vpn ipsec esp-group ESP-group proposal 1 encryption 'aes192gcm128'
set vpn ipsec esp-group ESP-group proposal 1 encryption 'aes128gcm128'
vyos@vyos:~$ sh ver
Version:          VyOS 2025.11.22-0019-rolling
Release train:    current
Release flavor:   generic

Built by:         autobuild@vyos.net
Built on:         Sat 22 Nov 2025 00:19 UTC
Build UUID:       1747e423-b4db-4cf1-bbef-3fc3e76520a8
Build commit ID:  dbee2b28dd03ff

Architecture:     x86_64
Boot via:         installed image
System type:      KVM guest
Secure Boot:      n/a (BIOS)

Hardware vendor:  QEMU
Hardware model:   Standard PC (i440FX + PIIX, 1996)

I can still reproduce the AES-GCM issue on a newer build.

VyOS:

Version: 1.5.0
Train: circinus
Build commit: cb47cdb72c6d08
Built on: 2026-03-30

VPP:

v25.10.0-48~vyos20260206142847.f850754fc

The problem seems to be the argument order used with
xfrmnl_sa_get_aead_params().

The libnl function signature is:

xfrmnl_sa_get_aead_params(
    sa, alg_name, key_len, icv_len, key);

Source:
https://github.com/thom311/libnl/blob/main/lib/xfrm/sa.c#L1678-L1710

The current VPP patch passes the arguments in this order:

xfrmnl_sa_get_aead_params(
    sa, alg_name, aead_icv_len, aead_key_len, key);

So key_len and icv_len are reversed.

For aes256gcm128, the values should be:

key_len = 288
icv_len = 128

With the current call, the variables instead contain:

aead_icv_len = 288
aead_key_len = 128

This is probably why aead_key_len was assumed to always be 128.

The later workaround checks key[32] and key[24] to guess the AES key
size:

if (key[32] != 0)
    AES-GCM-256;
else if (key[24] != 0)
    AES-GCM-192;
else
    AES-GCM-128;

That is not reliable. For AES-GCM-128 those offsets are outside the
valid 20-byte key+salt buffer. For AES-GCM-256, key[32] is the first
salt byte, which is allowed to be zero.

In my test, aes128gcm128 was installed correctly by Linux XFRM as:

16-byte AES key + 4-byte salt
total key length: 160 bits
ICV length: 128 bits

VPP imported the same SA as aes-gcm-256 with a 32-byte key. All inbound
ESP packets then failed decryption.

ESP pkts received: 5
ESP decryption failed: 5

After changing the ESP proposal to aes256gcm128, VPP imported the
32-byte key and 4-byte salt correctly. After clearing the counters,
inbound ESP decryption worked:

ESP pkts received: 2
ESP decryption failed: 0

The fix should be to pass the arguments in the correct order and use the
length returned by libnl:

ret = xfrmnl_sa_get_aead_params(
    sa, alg_name, aead_key_len, aead_icv_len, key);

switch (*aead_key_len)
  {
  case 160:
  case 224:
  case 288:
    *normalized_key_len = *aead_key_len;
    break;
  default:
    return -1;
  }

The expected mappings are:

160 bits -> AES-GCM-128
224 bits -> AES-GCM-192
288 bits -> AES-GCM-256

The algorithm should not be selected based on the contents of the key
or salt.