[Swan] Options for Windows clients

Alex mysqlstudent at gmail.com
Thu Dec 31 19:14:09 UTC 2020


Hi Manfred,

I got it to work subsequent to your email. I'll explain how I got it
to work, but my next issue is with DHCP.

> OK, so phase 1 passes.
> However, it still looks like Windows is sending multiple proposals,
> while when using Set-VpnConnectionIPsecConfiguration I think only one
> should be sent.
> Moreover:
> The relevant parameters of Set-VpnConnectionIPsecConfiguration at this
> stage (phase 1) are:
> -EncryptionMethod AES256
> -IntegrityCheckMethod SHA384
> -DHGroup Group14
> (The relevant part in the libreswan config is the ike=... line or its
> default value if not present.)
>
> -IntegrityCheckMethod SHA384 (as in you command below) does not match
> INTEG=HMAC_SHA2_256_128 which appears to be sent by Windows and logged
> as the accepted proposal by libreswan.

Here is a working example of using add/set-vpnconnection:
Add-VpnConnection -Name "ikev2-cp" -ServerAddress orion.example.com
-TunnelType "Ikev2" -PassThru -Force -EncryptionLevel "Required"
-AllUserConnection -AuthenticationMethod MachineCertificate
Set-VpnConnectionIPsecConfiguration
-ConnectionName "ikev2-cp"
-EncryptionMethod AES256
-DHGroup Group14
-IntegrityCheckMethod SHA384
-PfsGroup PFS2048
-AuthenticationTransformConstants SHA256128
-CipherTransformConstants AES256

The following also works, using these two changes:
-AuthenticationTransformConstants GCMAES256
-CipherTransformConstants GCMAES256

> > Dec 30 22:06:47.702497: "ikev2-cp"[2] 172.58.238.215 #3: processing
> > decrypted IKE_AUTH request: SK{IDi,CERT,CERTREQ,AUTH,CP,SA,TSi,TSr}
> > Dec 30 22:06:47.704044: "ikev2-cp"[2] 172.58.238.215 #3: certificate
> > verified OK: O=Example,CN=win10client.example.com
> > Dec 30 22:06:47.704103: "ikev2-cp"[2] 172.58.238.215 #3: IKEv2 mode
> > peer ID is ID_DER_ASN1_DN: 'CN=win10client.example.com, O=Example'
> > Dec 30 22:06:47.704669: "ikev2-cp"[2] 172.58.238.215 #3: authenticated
> > using RSA with SHA1
> Client authentication passes too. It says "RSA with SHA1", which should
> map to authby=rsasig in your conf file.

Turns out authby= isn't even necessary in order to work.

> The log shows that the (failing) proposal sent by Windows is
> 1:ESP:ENCR=AES_CBC_128;INTEG=HMAC_SHA1_96;ESN=DISABLED
>
> This does not match the parameters of Set-VpnConnectionIPsecConfiguration.
>
> It appears that Windows is not sending the proposals as required by
> Set-VpnConnectionIPsecConfiguration.
>  From the strongswan thread you posted earlier I remember the last
> comment about the manually tweaked registry entry overriding some
> parametres of Set-VpnConnectionIPsecConfiguration. Do you still have
> that registry entry in place?

I've tested it both with and without and it works either way. Looks
like it's not necessary (anymore?).

> On the libreswan side do you have an esp=... line in your config? If so
> compare that with the proposal sent by Windows. It looks like the phase
> 2 proposal sent by Windows has weak ciphers, though - meaning you may
> really want to change the registry rather than the esp=... line. Paul
> might be more specific on this.

Yes, just before your email I added the following:

esp=aes_gcm256-null,aes_gcm128-null,aes256-sha2_512,aes128-sha2_512,aes256-sha1,aes128-sha1,aes_gcm256-null

This was pulled from an Oct 2019 post to this list that included
modp1024 at the end that I stripped off here.

> > Here are the certutil commands I am now using:
> >
> > # generate CA certificate
> > echo "Generating CA certificate...."
> > certutil -z <(head -c 1024 /dev/urandom) \
> >          -S -x -n "Example CA" -s "O=Example,CN=Example CA" -k rsa \
> >          -g 4096 -v 36 -t "CT,," -2 -d /var/lib/ipsec/nss
> >
> > # generate orion client certificate
> > echo "Generating orion client certificate..."
> > certutil -z <(head -c 1024 /dev/urandom) \
> >          -S -c "Example CA" -n "orion.example.com" -s
> > "O=Example,CN=orion.example.com" \
> >          -k rsa -g 4096 -v 120 -t ",," -1 -6 -8 "orion.example.com" -d
> > /var/lib/ipsec/nss \
> >          --extSAN "ip:68.195.111.42" --keyUsage
> > "digitalSignature,keyEncipherment" \
> >          --extKeyUsage "serverAuth,ipsecIKEIntermediate"
> Option -1 is an alias for --keyUsage, since you are using --keyUsage
> with an explicit argument I would drop -1
> Same for option -6 and --extKeyUsage

it turns out --extKeyUsage is necessary - I went through the process
of recreating the entire thing then transferring the Windows cert
again, but it then produces the following error:

certificate O=Example,CN=Example CA failed IPsec verification
NSS ERROR: Peer's certificate has an invalid signature.

This is with "orion.example.com" set in the Windows connection issue.

> By adding -8 "orion.example.com" and --extSAN "ip:68.195.111.42" I
> believe you are adding two entries to the subjectAltName extension,
> resulting in something like:
> subjectAltName = "dns:orion.example.com,ip:68.195.111.42"
> This is technically correct, /if/ 68.195.111.42 is the IP address of the
> VPN gatweay as seen by the Windows client, however it might be more
> complicated that it needs be.
> You may verify that this is the actual result with
>    certutil -L -d sql:/var/lib/ipsec/nss -n "orion.example.com"

Yes, that's what it produced, but somehow appears necessary. btw, the
68.195.111.42 is the IP of the VPN gateway and 192.168.1.1 is its
internal gateway address.

> > certutil -z <(head -c 1024 /dev/urandom) \
> >          -S -c "Example CA" -n "win10client.example.com" \
> >          -s "O=Example,CN=win10client.example.com" -k rsa \
> >          -g 4096 -v 120 -t ",," -8 "win10client.example.com" -d
> > /var/lib/ipsec/nss \
> >          --extSAN "ip:68.195.111.42" --keyUsage
> > digitalSignature,keyEncipherment \
> >          --extKeyUsage "clientAuth"
>
> Same story about
> -8 "win10client.example.com"
> --extSAN "ip:68.195.111.42"

I've re-added this to the cert here too.

> However, this time the "ip:68.195.111.42" part is most probably wrong,
> because it should contain the IP address of the client, that can't be
> the same as the server's.
> Considering that the client may be a roadwarrior with dynamic IP, I
> would drop this part (--extSAN "ip:68.195.111.42") altogether.

Perhaps it was only the VPN server cert that this change was necessary.

> The first comment below is about the following two lines.
> > pk12util -o orion.example.com.p12 -n "orion.example.com" -d /var/lib/ipsec/nss
> > ipsec import orion.example.com.p12
>
> Two comments about -d /var/lib/ipsec/nss - only informational, don't let
> them confuse you:
> 1) If /var/lib/ipsec/nss is the default database path used by ipsec,
> then since you generate the server certificate in that database I think
> you don't need to export to p12 and import again in the same database.
> Take this with a grain of salt since I don't use certutil to create my
> certs.
>
> 2) creating the client certificate in /var/lib/ipsec/nss means you'll
> have that certificate in the default ipsec database too. This is not
> needed by libreswan. The client certificate is meant to be sent by the
> initiator(client) to the responder(server) which will validate it
> according to its trusted CA and requirements on client identity.
>
> The example in the libreswan page uses ${HOME}/tmpdb (IIRC) which is a
> private location in the user's home directory. Note that in this
> scenario the commands given take care of importing the applicable CA(s)
> together with the certificate - the server cert and CA in the ipsec
> database, and the client cert and CA to the Windows client.
>
> I'm not saying the way you're doing this above is wrong, just pointing
> out a couple of differences with the example in the libreswan page.

Understood. Makes sense. Works without it.

Okay, so here's the output from a working connection. An explanation
of what protocols are actually being used (chosen) here would be
helpful, just so I can better understand.

Dec 31 13:53:06.175169: "ikev2-cp"[1] 172.58.239.44: local IKE
proposals (IKE SA responder matching remote proposals):
Dec 31 13:53:06.175231: "ikev2-cp"[1] 172.58.239.44:
1:IKE=AES_GCM_C_256-HMAC_SHA2_512+HMAC_SHA2_256-NONE-MODP2048+MODP3072+MODP4096+MODP8192+ECP_256+ECP_384+ECP_521+CURVE25519
Dec 31 13:53:06.175245: "ikev2-cp"[1] 172.58.239.44:
2:IKE=AES_GCM_C_128-HMAC_SHA2_512+HMAC_SHA2_256-NONE-MODP2048+MODP3072+MODP4096+MODP8192+ECP_256+ECP_384+ECP_521+CURVE25519
Dec 31 13:53:06.175255: "ikev2-cp"[1] 172.58.239.44:
3:IKE=AES_CBC_256-HMAC_SHA2_512+HMAC_SHA2_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048+MODP3072+MODP4096+MODP8192+ECP_256+ECP_384+ECP_521+CURVE25519
Dec 31 13:53:06.175264: "ikev2-cp"[1] 172.58.239.44:
4:IKE=AES_CBC_128-HMAC_SHA2_512+HMAC_SHA2_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048+MODP3072+MODP4096+MODP8192+ECP_256+ECP_384+ECP_521+CURVE25519
Dec 31 13:53:06.175292: "ikev2-cp"[1] 172.58.239.44 #1: proposal
2:IKE=AES_CBC_256-HMAC_SHA2_256-HMAC_SHA2_256_128-MODP2048 chosen from
remote proposals
1:IKE:ENCR=AES_CBC_256;INTEG=HMAC_SHA1_96;PRF=HMAC_SHA1;DH=MODP2048
2:IKE:ENCR=AES_CBC_256;INTEG=HMAC_SHA2_256_128;PRF=HMAC_SHA2_256;DH=MODP2048[first-match]
3:IKE:ENCR=AES_CBC_256;INTEG=HMAC_SHA2_384_192;PRF=HMAC_SHA2_384;DH=MODP2048
Dec 31 13:53:06.180370: "ikev2-cp"[1] 172.58.239.44 #1: sent
IKE_SA_INIT reply {auth=IKEv2 cipher=AES_CBC_256
integ=HMAC_SHA2_256_128 prf=HMAC_SHA2_256 group=MODP2048}
Dec 31 13:53:06.338336: "ikev2-cp"[1] 172.58.239.44 #1: processing
decrypted IKE_AUTH request: SK{IDi,CERT,CERTREQ,AUTH,CP,SA,TSi,TSr}
Dec 31 13:53:06.338370: loading root certificate cache
Dec 31 13:53:06.342990: "ikev2-cp"[1] 172.58.239.44 #1: certificate
verified OK: O=Example,CN=win10client.example.com
Dec 31 13:53:06.343028: "ikev2-cp"[1] 172.58.239.44 #1: certificate
subjectAltName extension does not match ID_IPV4_ADDR '172.58.239.44'
Dec 31 13:53:06.343035: "ikev2-cp"[1] 172.58.239.44 #1: Peer CERT
payload SubjectAltName does not match peer ID for this connection
Dec 31 13:53:06.343038: "ikev2-cp"[1] 172.58.239.44 #1: X509:
connection failed due to unmatched IKE ID in certificate SAN
Dec 31 13:53:06.347987: "ikev2-cp"[1] 172.58.239.44 #1: reloaded
private key matching left certificate 'orion.example.com'
Dec 31 13:53:06.348005: "ikev2-cp"[1] 172.58.239.44 #1: switched from
"ikev2-cp"[1] 172.58.239.44 to "ikev2-cp"
Dec 31 13:53:06.348021: "ikev2-cp"[1] 172.58.239.44: deleting
connection instance with peer 172.58.239.44 {isakmp=#0/ipsec=#0}
Dec 31 13:53:06.348038: "ikev2-cp"[2] 172.58.239.44 #1: IKEv2 mode
peer ID is ID_DER_ASN1_DN: 'CN=win10client.example.com, O=Example'
Dec 31 13:53:06.348241: "ikev2-cp"[2] 172.58.239.44 #1: authenticated
using RSA with SHA1
Dec 31 13:53:06.370523: | pool 192.168.6.2-192.168.6.254: growing
address pool from 0 to 1
Dec 31 13:53:06.370591: "ikev2-cp"[2] 172.58.239.44: local ESP/AH
proposals (IKE_AUTH responder matching remote ESP/AH proposals):
Dec 31 13:53:06.370601: "ikev2-cp"[2] 172.58.239.44:
1:ESP=AES_GCM_C_256-NONE-NONE-DISABLED
Dec 31 13:53:06.370612: "ikev2-cp"[2] 172.58.239.44:
2:ESP=AES_GCM_C_128-NONE-NONE-DISABLED
Dec 31 13:53:06.370615: "ikev2-cp"[2] 172.58.239.44:
3:ESP=AES_CBC_256-HMAC_SHA2_512_256-NONE-DISABLED
Dec 31 13:53:06.370618: "ikev2-cp"[2] 172.58.239.44:
4:ESP=AES_CBC_128-HMAC_SHA2_512_256-NONE-DISABLED
Dec 31 13:53:06.370621: "ikev2-cp"[2] 172.58.239.44:
5:ESP=AES_CBC_256-HMAC_SHA1_96-NONE-DISABLED
Dec 31 13:53:06.370624: "ikev2-cp"[2] 172.58.239.44:
6:ESP=AES_CBC_128-HMAC_SHA1_96-NONE-DISABLED
Dec 31 13:53:06.370633: "ikev2-cp"[2] 172.58.239.44 #2: proposal
1:ESP=AES_CBC_128-HMAC_SHA1_96-DISABLED SPI=7e4be64a chosen from
remote proposals
1:ESP:ENCR=AES_CBC_128;INTEG=HMAC_SHA1_96;ESN=DISABLED[first-match]
Dec 31 13:53:06.432432: "ikev2-cp"[2] 172.58.239.44 #2: negotiated
connection [0.0.0.0-255.255.255.255:0-65535 0] ->
[192.168.6.2-192.168.6.2:0-65535 0]
Dec 31 13:53:06.432482: "ikev2-cp"[2] 172.58.239.44 #2: IPsec SA
established tunnel mode {ESPinUDP=>0x7e4be64a <0xa7eb30f0
xfrm=AES_CBC_128-HMAC_SHA1_96 NATOA=none NATD=172.58.239.44:28512
DPD=active}

Here is my working config. No ike= or authby= entry necessary.

conn ikev2-cp
    left=68.195.111.42
    leftcert=orion.example.com
    leftid=@68.195.111.42
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    leftrsasigkey=%cert
    right=%any
    rightaddresspool=192.168.6.2-192.168.6.254
    rightca=%same
    rightrsasigkey=%cert
    modecfgdns=8.8.8.8,193.100.157.123
    narrowing=yes
    dpddelay=30
    dpdtimeout=120
    dpdaction=clear
    auto=add
    ikev2=insist
    rekey=no
    fragmentation=yes
    esp=aes_gcm256-null,aes_gcm128-null,aes256-sha2_512,aes128-sha2_512,aes256-sha1,aes128-sha1,aes_gcm256-null

Here is my working script to produce the Windows certs:

#!/bin/bash
rm -f /var/lib/ipsec/nss/*db
ipsec initnss

# No password needed for database.
certutil -N -d /var/lib/ipsec/nss

echo "Generating CA certificate...."
certutil -z <(head -c 1024 /dev/urandom) \
        -S -x -n "Example CA" -s "O=Example,CN=Example CA" -k rsa \
        -g 4096 -v 36 -t "CT,," -2 -d /var/lib/ipsec/nss

echo "Generating orion client certificate..."
certutil -z <(head -c 1024 /dev/urandom) \
        -S -c "Example CA" -n "orion.example.com" -s
"O=Example,CN=orion.example.com" \
        -k rsa -g 4096 -v 120 -t ",," -8 "orion.example.com" -d
/var/lib/ipsec/nss \
        --keyUsage "digitalSignature,keyEncipherment" --extKeyUsage
"serverAuth,ipsecIKEIntermediate" \
        --extSAN "ip:68.195.111.42"

echo "Generating Windows certificate..."
certutil -z <(head -c 1024 /dev/urandom) \
        -S -c "Example CA" -n "win10client.example.com" \
        -s "O=Example,CN=win10client.example.com" -k rsa \
        -g 4096 -v 120 -t ",," -8 "win10client.example.com" -d
/var/lib/ipsec/nss \
        --keyUsage digitalSignature,keyEncipherment --extKeyUsage "clientAuth" \
        --extSAN "ip:68.195.111.42"

certutil -L -d /var/lib/ipsec/nss

pk12util -o win10client.example.com.p12 -n "win10client.example.com"
-d /var/lib/ipsec/nss
#pk12util -o orion.example.com.p12 -n "orion.example.com" -d /var/lib/ipsec/nss
#ipsec import orion.example.com.p12

Can we add some of this to the wiki so someone else doesn't have to go
through all of this? There's no way the wiki entry would work as it is
currently.

I also want to experiment a bit more with the add/set-vpnconnection
commands - it seems unreasonable for end-users to have to enter those
commands.


More information about the Swan mailing list