IPSec always sounded like a nightmare to me, at least, as a long time user of OpenVPN I never understood why it is so complicated.
But hello GCE, AWS and customer asking me to join on-premise networks to their cloud provider. There’s no alternative here, but IPSec. If you don’t want to do it on Cisco (or assimilated devices) there’s StrongSwan on Linux but there’s a huge pitfall and I wanted to write about it.
Usually, you start having cipher negotiation issue and StrongSwan logging is to say the least, not helpful.
Debian tricked me
Today I was connecting a Google Cloud to a Debian-based gateway with StrongSwan and as expected I got cipher issue:
ipsec up gce-vpn initiating IKE_SA gce-vpn to 188.8.131.52 generating IKE_SA_INIT request 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(FRAG_SUP) N(HASH_ALG) N(REDIR_SUP) ] sending packet: from 127.0.0.1 to 184.108.40.206 (874 bytes) received packet: from 220.127.116.11 to 127.0.0.1 (712 bytes) parsed IKE_SA_INIT response 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(FRAG_SUP) N(HASH_ALG) N(MULT_AUTH) ] selected proposal: IKE:AES_GCM_16_256/PRF_HMAC_SHA2_512/MODP_4096 ENCRYPTION_ALGORITHM AES_GCM_16 (key size 256) not supported! key derivation failed establishing connection 'gce-vpn' failed
So the first question was, is AES_GCM_16 not supported on my side or on Google side ? Cryptic messages did not help but I assumed it was on my side as when it comes from the other side the message is usually “NO_PROPOSAL_CHOSEN”.
How do I check supported ciphers ?
ipsec listalgs List of registered IKE algorithms: encryption: AES_CBC[aes] RC2_CBC[rc2] integrity: AES_XCBC_96[xcbc] HMAC_SHA1_96[hmac] HMAC_SHA1_128[hmac] HMAC_SHA1_160[hmac] HMAC_MD5_96[hmac] HMAC_MD5_128[hmac] HMAC_SHA2_256_128[hmac] HMAC_SHA2_256_256[hmac] HMAC_SHA2_384_192[hmac] HMAC_SHA2_384_384[hmac] HMAC_SHA2_512_256[hmac] HMAC_SHA2_512_512[hmac] aead: hasher: HASH_SHA1[sha1] HASH_SHA2_224[sha2] HASH_SHA2_256[sha2] HASH_SHA2_384[sha2] HASH_SHA2_512[sha2] HASH_MD5[md5] prf: PRF_KEYED_SHA1[sha1] PRF_FIPS_SHA1_160[fips-prf] PRF_AES128_XCBC[xcbc] PRF_HMAC_SHA1[hmac] PRF_HMAC_MD5[hmac] PRF_HMAC_SHA2_256[hmac] PRF_HMAC_SHA2_384[hmac] PRF_HMAC_SHA2_512[hmac] xof: XOF_MGF1_SHA1[mgf1] XOF_MGF1_SHA224[mgf1] XOF_MGF1_SHA256[mgf1] XOF_MGF1_SHA384[mgf1] XOF_MGF1_SHA512[mgf1] dh-group: MODP_3072[gmp] MODP_4096[gmp] MODP_6144[gmp] MODP_8192[gmp] MODP_2048[gmp] MODP_2048_224[gmp] MODP_2048_256[gmp] MODP_1536[gmp] MODP_1024[gmp] MODP_1024_160[gmp] MODP_768[gmp] MODP_CUSTOM[gmp] random-gen: RNG_STRONG[random] RNG_TRUE[random] nonce-gen: [nonce]
Indeed, I cannot see anything related to GCM, looks being the root of my issue.
Investigations and resolution
I wanted to verify first if this cipher is supposed to be supported by StrongWan and found the answer here:
It needs “aes” and “gcm” plugins, so let’s read more about StrongSwan plugins
Ok that’s interresting. Aes should be ok, but gcm is disabled by default. I need to check what Debian did here, and verify the gcm plugin is enabled.
Debian developers usually store their packaging files on Debian’s internal public GitLab server which is called Salsa. Strongswan packaging is hosted here, so it was easy to check:
debian/rules file is in charge of building the package, so this is what you want to check for options passed ton autotools configure script. Here we can clearly see gcm plugin is explicitly enabled.
I also checked debian/changelog to be sure it was already enabled in the stable version of the package which is available on Debian Buster, and yes, it was…
So why do I missed it ?
I check installed strongswan packages and found *libstrongswan*, let’s see it content
dpkg -L libstrongswan [...] /usr/lib/ipsec/plugins/libstrongswan-aes.so /usr/lib/ipsec/plugins/libstrongswan-attr.so /usr/lib/ipsec/plugins/libstrongswan-constraints.so [...]
This is very interesting ! The aes plugin file is here, but no gcm one. Let’s check if it’s available (i’ll just guess its name) anywhere in the Debian archive ?
apt install apt-file apt-file update apt-file search libstrongswan-gcm.so libstrongswan-standard-plugins: /usr/lib/ipsec/plugins/libstrongswan-gcm.so
I felt stupid here… This is quite common in Debian to separate the “standard” files from the “minimal” ones.
After installing the package and restarting strongswan the list of supported cipher is quite different:
apt install libstrongswan-standard-plugins systemctl restart strongswan ipsec listalgs List of registered IKE algorithms: encryption: AES_CBC[aesni] AES_CTR[aesni] RC2_CBC[rc2] 3DES_CBC[openssl] CAMELLIA_CBC[openssl] CAST_CBC[openssl] BLOWFISH_CBC[openssl] DES_CBC[openssl] DES_ECB[openssl] NULL[openssl] integrity: AES_XCBC_96[aesni] AES_CMAC_96[aesni] HMAC_MD5_96[openssl] HMAC_MD5_128[openssl] HMAC_SHA1_96[openssl] HMAC_SHA1_128[openssl] HMAC_SHA1_160[openssl] HMAC_SHA2_256_128[openssl] HMAC_SHA2_256_256[openssl] HMAC_SHA2_384_192[openssl] HMAC_SHA2_384_384[openssl] HMAC_SHA2_512_256[openssl] HMAC_SHA2_512_512[openssl] CAMELLIA_XCBC_96[xcbc] aead: AES_CCM_8[aesni] AES_CCM_12[aesni] AES_CCM_16[aesni] AES_GCM_8[aesni] AES_GCM_12[aesni] AES_GCM_16[aesni] hasher: HASH_SHA1[sha1] HASH_SHA2_224[sha2] HASH_SHA2_256[sha2] HASH_SHA2_384[sha2] HASH_SHA2_512[sha2] HASH_MD5[md5] HASH_MD4[openssl] HASH_IDENTITY[openssl] prf: PRF_AES128_XCBC[aesni] PRF_AES128_CMAC[aesni] PRF_KEYED_SHA1[sha1] PRF_HMAC_MD5[openssl] PRF_HMAC_SHA1[openssl] PRF_HMAC_SHA2_256[openssl] PRF_HMAC_SHA2_384[openssl] PRF_HMAC_SHA2_512[openssl] PRF_FIPS_SHA1_160[fips-prf] PRF_CAMELLIA128_XCBC[xcbc] xof: XOF_MGF1_SHA1[mgf1] XOF_MGF1_SHA224[mgf1] XOF_MGF1_SHA256[mgf1] XOF_MGF1_SHA384[mgf1] XOF_MGF1_SHA512[mgf1] dh-group: ECP_256[openssl] ECP_384[openssl] ECP_521[openssl] ECP_224[openssl] ECP_192[openssl] ECP_256_BP[openssl] ECP_384_BP[openssl] ECP_512_BP[openssl] ECP_224_BP[openssl] MODP_3072[openssl] MODP_4096[openssl] MODP_6144[openssl] MODP_8192[openssl] MODP_2048[openssl] MODP_2048_224[openssl] MODP_2048_256[openssl] MODP_1536[openssl] MODP_1024[openssl] MODP_1024_160[openssl] MODP_768[openssl] MODP_CUSTOM[openssl] CURVE_25519[openssl] CURVE_448[openssl] random-gen: RNG_WEAK[openssl] RNG_STRONG[random] RNG_TRUE[random] nonce-gen: [nonce]
And the VPN now works !