HOWTO: Using NSS with libreswan
The libreswan IKE daemon uses the Mozilla Network Security Services ("NSS") crypto library for all cryptographic functions during the IKE negotiation.
Introduction
NSS is a userspace library utilized by the libreswan IKE daemon 'pluto' for cryptographic operations. NSS does not handle the IPsec crypto operations inside of the kernel; these are handled seperately by NETKEY or the KLIPS kernel module.
The NSS library exports a PKCS#11 API for the application to communicate to a cryptographic device. The cryptographic device is usually the "soft token" but can also be a Hardware Security Module (HSM).
The advantage of using NSS is that pluto does not need to know in detail how the cryptographic device works. Pluto does not access any private keys or data itself. Instead, it uses the PK11 wrapper API of NSS irrespective of the cryptographic device used. Pluto hands over work using the PK11 interface to NSS and never has direct access to the private key material itself. Both IKEv1 and IKEv2 operations are performed using NSS. Private RSA keys (raw RSA as well as X.509 based private RSA keys) are stored inside NSS and those are not referenced in /etc/ipsec.secrets. X.509 keys and certificates are referenced using their "nickname" instead of their filename in /etc/ipsec.conf.
While PreShared Key (PSK) calculations are done using NSS, the actual preshared key ("secret") is still stored in /etc/ipsec.secrets.
NSS as shipped by Red Hat is a FIPS certified library. Libreswan is currently in the process of obtaining a FIPS certification for http://www.redhat.com/products/enterprise-linux/ [RHEL7].
If you are migrating from openswan with NSS or libreswan 3.13 or older to libreswan 3.14, then you will be converted to the new NSS SQL database format. See 3.14_X509 |
NSS command line tools
- certutil: Look and modify the NSS db. "ipsec initnss" and "ipsec look" use certutil under the hood.
- pk12util: import and export certificates and keys from and to the NSS db. The "ipsec import" command is a simple wrapper around this utility.
- modutil: Put NSS into FIPS mode
- crlutil: import CRLs into the NSS db.
Creating the NSS db for use with libreswan
If you are not using a packaged libreswan version, you might need to create a new NSS db before you can start libreswan. This can be done using:
ipsec initnss
By default the NSS db is created in /etc/ipsec.d/
When creating a database, you are prompted for a password. The default libreswan package install for RHEL/Fedora/CentOS uses an empty password. It is up to the administrator to decide on whether to use a password or not. However, a non-empty database password must be provided when running in FIPS mode.
To change the empty password, run:
certutil -W -d sql:/etc/ipsec.d
Enter return for the "old password", then enter your new password twice.
If you create the database with a password, and want to run NSS in FIPS mode, you must create a password file with the name "nsspassword" in the /etc/ipsec.d direcotry before starting libreswan. The "nsspassword" file must contain the password you provided when creating NSS database.
If the NSS db is protected with a non-empty password, the "nsspassword" file must exist for pluto to start. The syntax of the "nsspassword" file is:
token_1_name:the_password token_2_name:the_password
The name of NSS softtoken (the default software NSS db) when NOT running in FIPS mode is "NSS Certificate DB". If you wish to use software NSS db with password "secret", you would have the following entry in the nsspassword file:
NSS Certificate DB:secret
If running NSS in FIPS mode, the name of NSS softtoken is "NSS FIPS 140-2 Certificate DB". If there are smartcards in the system, the entries for passwords should be entered in this file as well.
Do not enter any spaces before or after the token name or password |
Using raw RSA keys with NSS
The "ipsec newhostkey" and "ipsec rsasigkey" utilities are used for creating raw RSA keys. If a non-default NSS directory is used, this can be specified using the -d option.
ipsec newhostkey --nssdir /etc/ipsec.d [--password password] \ --output /etc/ipsec.secrets
As of libreswan 3.21 you no longer need to use the --output command, as ipsec.secrets entries are no longer required |
The password is only required if the NSS database is protected with a non-empty password. All "private" compontents of the raw RSA key in /etc/ipsec.secrets such as the exponents and primes are filled in with the CKA ID, which serves as an identifier for NSS to look up the proper information in the NSS db during the IKE negotiation.
Public key information is directly available in /etc/ipsec.secrets and the "ipsec showhostkey" command can be used to generate left/rightrsasigkey= entries for /etc/ipsec.conf.
# ipsec showhostkey --list < 1> RSA keyid: AwEAAbScF ckaid: 2ad438fc7f3b65706f0381520f9f106a9eba7a96 # ipsec showhostkey --left --ckaid 2ad438fc7f3b65706f0381520f9f106a9eba7a96 # rsakey AwEAAbScF leftrsasigkey=0sAwEAAbScFcIsVh6ee/nd7n4VEBRWnpuxefzzDFktmikoUcO76/gql0f67ySeugs8B/N7u/Jcn7NoOJmDZrcD4p5t2Qddzw5yl1sd2na6vN/eQvCFPrjHz6qX67qx+jExe8Jd6UxvwQC3bzGkJr8vt3sWpsUyfNsNdoxO7tE5uzumHv2Cm9Cwts80k4+I+qF1bKALY5jn/xAR1UGhZDxymfYfNJm0+dSmzMp8J9yw9fN5tt6eUKB/cuRHn7wfKEAd2E9PYcLeXaDnMJHyslIIxK5GXRK0nNGxMqPdJIzp4t1jBOJhd6HMEiaW9K08hVdwiz9pMTIM+DDhPvtMueR2WZ7KUSM=
The leftrsasigkey= can now be used in a connection configuration in ipsec.conf.
Using certificates with NSS
Any X.509 certificate management system can be used to generate Certificate Agencies, certificates, pkcs12 files and CRLs. Common tools people use are the openssl command, the GTK utility tinyca2, or the NSS certutil command.
An example using openssl can be found as part of the libreswan test suite at
Below, we will be using the nss tools to generate certificates
To create a certificate authority (CA certficate)
certutil -S -k rsa -n "ExampleCA" -s "CN=Example CA Inc" -v 12 \ -t "CT,C,C" -x -d sql:/etc/ipsec.d
It creates a certificate with RSA keys (-k rsa) with the nick name "ExampleCA", and with common name "Example CA Inc". The option "-v" specifies the certificates validity period. "-t" specifies the attributes of the certificate. "C" is required for creating a CA certificate. "-x" means self signed. "-d" specifies the path of the database directory.
It is not a requirement to create the CA in NSS database. The CA certificate can be obtained from third parties
To create a user certificate signed by the above CA
certutil -S -k rsa -c "ExampleCA" -n "user1" -s "CN=User Common Name" \ -v 12 -t "u,u,u" -d sql:/etc/ipsec.d
This creates a user cert with nick name "user1" with attributes "u,u,u" signed by the CA cert "ExampleCA".
You must provide a nick name when creating a user certificate, because pluto reads the user certificate from the NSS database based on the user certificate's nickname |
Configuring certificates in ipsec.conf and ipsec.secrets
In ipsec.conf, the leftcert= option takes a certificate nickname as argument. For example if the nickname of the user cert is "hugh", then it can be "leftcert=hugh".
If you are migrating from openswan without NSS, you were used to specify the filename for the certificate in the leftcert= option. Filenames are not valid in libreswan - only the nickname can be used.
leftcert=nickname
On Libreswan version 3.15 and older it is required to add entry in ipsec.secrets. We need to list the certificate nickname to inform pluto there is a certificate within the NSS db. This is specified using:
: RSA nickname
In openswan and freeswan without NSS it was required to specify a file name or password. With libreswan, this is not required. Private keys were stored in /etc/ipsec.d/private/ This directory is also not used with libreswan.
The directories /etc/ipsec.d/cacerts/ and /etc/ipsec.d/crls/ can still be used.
NOTE: the freeswan and openswan directories /etc/ipsec.d/aacerts/ and /etc/ipsec.d/acerts/ are not used with libreswan.
If you use an external CA certificate, you can either import it into the NSS db or place it in the /etc/ipsec.d/cacerts/ directory. Note that the preferred method is to store it inside the NSS db.
Importing third-party files into NSS
Importing user credentials (.crt, .key and .p12 files)
If you do not have the third-party certificate in the PKCS#12 format, use openssl to create a PKCS#12 file:
openssl pkcs12 -export -in cert.pem -inkey key.pem \ -certfile cacert.pem -out YourName.p12 [-name YourName]
Now you can import the file into the NSS db:
ipsec import YourName.p12
NOTE: the ipsec import command uses "pk12util -i YourName.p12 -d sql:/etc/ipsec.d"
If you did not pick a name using the -name option, you can use certutil -L -d /etc/ipsec.d to figure out the name NSS picked durnig the import.
To specify the certificate in ipsec.conf, use a line like:
leftcert=YourName
If you use libreswan 3.15 or older then add following to /etc/ipsec.secrets file to load private key. This is not necessary on later versions:
: RSA "YourName"
Importing CAcerts
The CAname is a friendly_name to refer to the CA certificate inside NSS. If your NSS db is procted by a password, specify it as the last item on the command line. For DER formatted certificates use:
certutil -A -i /path/YourCA.der -d sql:/etc/ipsec.d -n "CAname" -t 'CT,,'
For PEM formatted CA certificates use:
certutil -A -a -i /path/YourCA.pem -d sql:/etc/ipsec.d -n "CAname" -t 'CT,,'
Importing CRLs
For pem files use:
crlutil -I -i /path/yourcrl.der -d sql:/etc/ipsec.d -a -B
For dir files use:
crlutil -I -i /path/yourcrl.der -d sql:/etc/ipsec.d -B
CRLs signed by a root CA are only processed if the root CA is marked as Trusted in NSS - See previous section |
Exporting a CA(?) certificate to load on another libreswan machine
Paul: wouldn't this also include the private key which we don't want? Paul: add "ipsec export"?
To export the CA certificate, including the private key:
pk12util -o cacert1.p12 -n cacert1 -d sql:/etc/ipsec.d
Normally you would just want the CA cert. To extract just the CA cert without the private key:
certutil -L -n "CA nickname" -d sql:/etc/ipsec.d/ -a > theca.crt
You can also use -x instead of -a for binary DER encoding.
Copy the .p12 or .crt file to the new machine.
To import the .crt file:
certutil -A -i theca.crt -n "CA nickname" -t "CT,," -d /etc/ipsec.d/
To import the .p12 file:
ipsec import cacert1.p12 certutil -M -n cacert1 -t "CT,," -d sql:/etc/ipsec.d
An example connection for ipsec.conf would look like:
conn pluto-1-2 left=1.2.3.4 leftid="CN=usercert1" leftrsasigkey=%cert leftcert=usercert1 right=5.6.7.8 rightid="CN=usercert2" rightrsasigkey=%cert auto=add
Configuring a smartcard with NSS
Required library: libcoolkey or other PKCS#11 compatible library
To make smartcard tokens visible through NSS
modutil -add <module_name> -libfile libcoolkeypk11.so \ -dbdir <nss_database_dir_name> \ -mechanisms <mechanisms_separted_by_colons>
An example of mechanisms can be: RC2:RC4:DES:DH:SHA1:MD5:MD2:SSL:TLS:AES:CAMELLIA.
To check whether the token is visible or not, run
modutil -list -dbdir <nss_database_dir_name>
Using NSS in FIPS mode
If the system is running in FIPS mode, the NSS library and libreswan will automatically also run in FIPS mode. To check if libreswan is running in FIPS mode, run:
ipsec whack --fipsstatus
To see more detailed information about the FIPS status of the operating system and libreswan, the selfcheck command can be run:
# ipsec pluto --selftest Pluto initialized FIPS Product: NO FIPS Kernel: NO FIPS Mode: NO [...] FIPS HMAC integrity support [enabled] FIPS mode disabled for pluto daemon FIPS HMAC integrity verification self-test passed [...] Encryption algorithms: AES_CCM_16 IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_ccm, aes_ccm_c AES_CCM_12 IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_ccm_b AES_CCM_8 IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_ccm_a 3DES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS [*192] 3des CAMELLIA_CTR IKEv1: ESP IKEv2: ESP {256,192,*128} CAMELLIA_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} camellia AES_GCM_16 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm, aes_gcm_c AES_GCM_12 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_b AES_GCM_8 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_a AES_CTR IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aesctr AES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aes SERPENT_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} serpent TWOFISH_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} twofish TWOFISH_SSH IKEv1: IKE IKEv2: IKE ESP {256,192,*128} twofish_cbc_ssh NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac NULL IKEv1: ESP IKEv2: ESP [] CHACHA20_POLY1305 IKEv1: IKEv2: IKE ESP [*256] chacha20poly1305 Hash algorithms: MD5 IKEv1: IKE IKEv2: SHA1 IKEv1: IKE IKEv2: FIPS sha SHA2_256 IKEv1: IKE IKEv2: FIPS sha2, sha256 SHA2_384 IKEv1: IKE IKEv2: FIPS sha384 SHA2_512 IKEv1: IKE IKEv2: FIPS sha512 PRF algorithms: HMAC_MD5 IKEv1: IKE IKEv2: IKE md5 HMAC_SHA1 IKEv1: IKE IKEv2: IKE FIPS sha, sha1 HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256 HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384 HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512 AES_XCBC IKEv1: IKEv2: IKE aes128_xcbc Integrity algorithms: HMAC_MD5_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH md5, hmac_md5 HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1 HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, sha2_512_256, hmac_sha2_512 HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, sha2_384_192, hmac_sha2_384 HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256 HMAC_SHA2_256_TRUNCBUG IKEv1: ESP AH IKEv2: AH AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH aes_xcbc, aes128_xcbc, aes128_xcbc_96 AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac NONE IKEv1: ESP IKEv2: IKE ESP FIPS null DH algorithms: NONE IKEv1: IKEv2: IKE ESP AH FIPS null, dh0 MODP1536 IKEv1: IKE ESP AH IKEv2: IKE ESP AH dh5 MODP2048 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh14 MODP3072 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh15 MODP4096 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh16 MODP6144 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh17 MODP8192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh18 DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256, ecp256 DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384, ecp384 DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521, ecp521 DH31 IKEv1: IKE IKEv2: IKE ESP AH curve25519 testing CAMELLIA_CBC: Camellia: 16 bytes with 128-bit key Camellia: 16 bytes with 128-bit key Camellia: 16 bytes with 256-bit key Camellia: 16 bytes with 256-bit key testing AES_GCM_16: empty string one block two blocks two blocks with associated data testing AES_CTR: Encrypting 16 octets using AES-CTR with 128-bit key Encrypting 32 octets using AES-CTR with 128-bit key Encrypting 36 octets using AES-CTR with 128-bit key Encrypting 16 octets using AES-CTR with 192-bit key Encrypting 32 octets using AES-CTR with 192-bit key Encrypting 36 octets using AES-CTR with 192-bit key Encrypting 16 octets using AES-CTR with 256-bit key Encrypting 32 octets using AES-CTR with 256-bit key Encrypting 36 octets using AES-CTR with 256-bit key testing AES_CBC: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key Encrypting 32 bytes (2 blocks) using AES-CBC with 128-bit key Encrypting 48 bytes (3 blocks) using AES-CBC with 128-bit key Encrypting 64 bytes (4 blocks) using AES-CBC with 128-bit key testing AES_XCBC: RFC 3566 Test Case 1: AES-XCBC-MAC-96 with 0-byte input RFC 3566 Test Case 2: AES-XCBC-MAC-96 with 3-byte input RFC 3566 Test Case 3: AES-XCBC-MAC-96 with 16-byte input RFC 3566 Test Case 4: AES-XCBC-MAC-96 with 20-byte input RFC 3566 Test Case 5: AES-XCBC-MAC-96 with 32-byte input RFC 3566 Test Case 6: AES-XCBC-MAC-96 with 34-byte input RFC 3566 Test Case 7: AES-XCBC-MAC-96 with 1000-byte input RFC 4434 Test Case AES-XCBC-PRF-128 with 20-byte input (key length 16) RFC 4434 Test Case AES-XCBC-PRF-128 with 20-byte input (key length 10) RFC 4434 Test Case AES-XCBC-PRF-128 with 20-byte input (key length 18) testing HMAC_MD5: RFC 2104: MD5_HMAC test 1 RFC 2104: MD5_HMAC test 2 RFC 2104: MD5_HMAC test 3
For example using RHEL8/CentOS8, placing the system in FIPS mode using the following commands is enough for libreswan to run in FIPS mode:
fips-mode-setup --enable reboot
If the Linux distribution offers no easy way to place the system in FIPS mode, this can be done manually. For the Operating System to be considered in FIPS mode, the Linux kernel (compiled with FIPS support) must have been booted with the kernel command option fips=1 and the file /etc/system-fips needs to exist (but can be 0 bytes in size). The system-fips file is often created by dracut-fips. Additionally, the NSS database has to be (re)configured to be in FIPS mode. This can be done using:
modutil -dbdir sql:/etc/ipsec.d -fips true -force
To check if the NSS database is in FIPS mode, use:
modutil -dbdir sql:/etc/ipsec.d -chkfips true