How to protect the Google Chrome NSS Certificate DB store in Linux with password

Google Chrome for Linux, keeps the installed X.509 certificates and keys in NSS Certificate DB store, which is not protected by default. That means, everyone with access to the browser and/or the user's home directory, can copy the signing keys. The goal of this memo is to explain how to protect the Google Chrome's certificate store with password.

Note, that the folder, where Google Chrome keeps the NSS Certificate DB files per user is:

${HOME}/.pki/nssdb

During its first start (initiated by the user), the browser generates the NSS Certificate DB store files there in:

cert9.db
key4.db
pkcs11.txt

It is very important to keep in mind that Google Chrome uses SQLite3-based format of NSS Certificate DB, when using the NSS tools to manage the database.

To list the content of the database, use the tool certutil (mind the file system locator "sql:" that is after "-d" in the command line bellow):

$ certutil -L -d sql:${HOME}/.pki/nssdb

If there are X.509 certificates installed in NSS Certificate DB, you will see their friendly names and trust attributes (otherwise, only the column descriptions will be displayed).

To set the password for protecting the keys and the integrity of NSS Certificate DB, stop Google Chrome first (check if it is running), and then execute the following command line:

$ certutil -W -d sql:${HOME}/.pki/nssdb

That will start a dialogue in the terminal. At the beginning, you will need to type the current password (simply press "Enter" to try the default password, which is an empty string):

Enter Password or Pin for "NSS Certificate DB":

If that is the correct password, the next step will begin with the following statement displayed:

Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.

followed by a prompt, where the new password for protecting NSS Certificate DB to be entered twice:

Enter new password:
Re-enter password:

If the new password is correctly typed, a confirmation message will be displayed:

Password changed successfully.

From this moment onward, the installation of new certificates (with or without their private keys) in NSS Certificate DB, as well as the access to the installed private keys, will be granted based on password.

To verify the password controlled access to the NSS Certificate DB is working, run Google Chrome, type in the address bar:

chrome://settings/certificates

and press "Enter". If NSS Certificate DB is password protected, the following window will appear on the screen:

(note the window description saying "Please sign in to NSS Certificate DB"). In case you cannot provide the correct password, only read-only access to the NSS Certificate DB will be granted, with no access to the private keys installed there (that means no certificate authenticated logins, no digital signatures).

What if I forget the password for NSS Certificate DB?

You cannot do much, because the private keys, previously installed in the database, are now encrypted with a password you have forgotten. Moreover, the password is irretrievable, since no additional decryption key or another mechanism, that might help to retrieve the password from the locked database files exists, as a part of the NSS Certificate DB design. Hence, if you forget the NSS Certificate DB password, consider the keys installed in there lost.

In case you keep backup copies of the certificates and keys (as PFX/PKCS#12 files), you might create a new database and install them there. To create new NSS Certificate DB, you need to stop Google Chrome (mandatory). Then move the old NSS Certificate DB files to a temporary location (who knows, one day the forgotten password might be found):

$ mkdir ${HOME}/.pki/nssdb-lost
$ mv ${HOME}/.pki/nssdb/* ${HOME}/.pki/nssdb-lost/

and create new database files in ${HOME}/.pki/nssdb:

$ certutil -N -d sql:${HOME}/.pki/nssdb

After the message:

Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.

enter the new password twice:

Enter new password:
Re-enter password:

and if the confirmation message:

Password changed successfully.

is displayed, you new (but empty) NSS Certificate DB, is created and protected with password.

Now you can run the Google Chrome and install the certificates and private keys, using the NSS Certificate DB management tools, embedded in the browser.


SmartCard-HSM USB token: Using Smart Card Shell 3 for initializing and configuring the token, generating key pairs, and importing keys and X.509 certificates from external PKCS#12 containers

Content:

  1. Introduction
  2. Prerequisites
  3. Downloading and installing Smart Card Shell 3
  4. Running Smart Card Shell 3 GUI
  5. Loading the key manager in Smart Card Shell 3 GUI
  6. Initializing the token and configuring DKEK to enable the import of keys and X.509 certificates from PKCS#12 files
  7. Generating ECC key pair (by means of DKEK shares)
  8. Importing key pair and the corresponding X.509 certificate from PKCS#12 file into the token (by means of DKEK shares)

 

1. Introduction

The SmardCard-HSM (Standard-A USB) token (you can order it online):

is a reliable, fast, secure, and OpenSC compatible HSM device, for generating, storing, and importing RSA, AES, and Elliptic Curve (EC) keys and X.509 certificates. Maybe, the best feature of the device is its enhanced support for EC (up to 521-bit keys), and the ability to import key pairs and certificates from PKCS#12 containers. Later allows to clone a key pair into several token devices, as a hardware backup scenario.

Unfortunately, the vendor does not provide (yet) a comprehensive documentation for end users, describing in details the specific process of importing key pairs and X.509 certificates from PKCS#12 containers (files) into the token (which is something very much in demand). Therefore, the goal of this document is to fix (at least partially) that gap in the documentation.

Note, that the procedures, described above, are not part of the everyday practice. They are required only for initializing the token device, generating EC keys for curves that are not currently listed as supported in the token's firmware (for instance, secp384r1 curve is supported by the token's processor, but not listed as supported in the firmware and the OpenSC based tools cannot request secp384r1 key generation), and to import key pairs and X.509 certificates from PKCS#12 files.

 

2. Prerequisites

To be able to follow the steps given below, you need to have installed and updated Linux distribution, running a Graphical Desktop environment (GNOME, KDE). Recent OpenJDK (17 is recommended if available) must be installed and kept updated. Do not install OpenJDK manually, since it is an essential software package! Always use the package manager, provided by the vendor of your Linux distribution to install or update OpenJDK:

  • RHEL7, CentOS 7, Scientific Linux 7:

    # yum install java-11-openjdk.x86_64
  • Fedora (current), RHEL8/9, CentOS 8, Scientific Linux 8, Rocky Linux 8/9, Alma Linux 9:

    # dnf install java-17-openjdk.x86_64
  • Ubuntu:

    # apt-get install openjdk-17-jdk-headless

It is not a good idea to configure the HSM token and manage its content on a system, that is used for social networking, software testing, gaming, or any other activity, that might be considered risky in this case. Always use a dedicated desktop system (or dedicated Linux virtual machine) for managing your PKI infrastructure.

You might have more than one version of OpenJDK installed on your system. So the first step is to check that and set the latest OpenJDK as a default Java provider. Execute the following command line (be super user or root):

# alternatives --config java

to check how many Java packages (provides) are installed and available locally, and which one of them is set as current default. For example, the following result:

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*+ 1           java-11-openjdk.x86_64 (/usr/lib/jvm/java-11-openjdk-11.0.19.0.7-1.el9_1.x86_64/bin/java)
   2           java-17-openjdk.x86_64 (/usr/lib/jvm/java-17-openjdk-17.0.7.0.7-1.el9_1.x86_64/bin/java)


Enter to keep the current selection[+], or type selection number:

means there are two OpenJDK packages installed, and the first one is set a default Java provider (see which is the entry marked with "+" in the first column). To set OpenJDK 17 default Java provider, type the ID number assigned to the package in the list (in the "Selection" column) and press "Enter" afterwards (in the above example, the ID used is 2):

Enter to keep the current selection[+], or type selection number: 2

It is always a good idea to check if the symlinks created by the alternatives tool points to the correct target. The simplest way to do so for OpenJDK 11 is to follow the symlink /etc/alternatives/java:

$ ls -al /etc/alternatives/java

and verify that the target is the OpenJDK 11 java executable:

lrwxrwxrwx. 1 root root 63 Apr 29 13:58 /etc/alternatives/java -> /usr/lib/jvm/java-17-openjdk-17.0.7.0.7-1.el9_1.x86_64/bin/java

Also check if the Java major version of the target:

$ java --version

is 17:

openjdk 17.0.7 2023-04-18 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.7.0.7-1.el9_1) (build 17.0.7+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-17.0.7.0.7-1.el9_1) (build 17.0.7+7-LTS, mixed mode, sharing)

Also, have pcscd running.

 

3. Downloading and installing Smart Card Shell 3

Be sure you have OpenJDK 17 installed, as specified above. Then visit the web page:

https://www.openscdp.org/scsh3/download.html

click on "IzPack Installer" link, and save locally the provided JAR archive of the installer.

Decide what kind of installation of Smart Card Shell 3 do you really need - to allow all users of the system to run the program code (run the installer as super user), or to limit that ability to a certain unprivileged user (perform the installation using that particular user ID):

  • run the installer as super user (root):

    You should install the program into a system folder, where the users can only read and execute the Java code (no write access should be given by default). That kind of restrictions will protect the executable code from deletion of modification.

  • run the installer as a non-privileged user:

    In this case, the simplest solution is to install the program into the home folder of the user. That type of installation is recommended only for a user, who really understands how to keep the executable code safe.

If followed, the steps given bellow will install the executable code of the program in the home folder of those user, who is executing the installer.

Open a terminal and type:

$ java -jar /path/to/scsh3.XX.YYY.jar

(here XX and YYY are numbers, unique for the current version). The following window will appear (press there the button "Next" to continue):

Select the installation folder (use the button "Browse" to change it, if you do not like the one suggested by the installer), and press "Next":

Now you will be able to see the progress of the installation process (press the button "Next" to continue, when it is done):

Next, you need to decide whether or not to create a shortcut to the program in the GNOME "Applications" menu (it is recommended to create such a shortcut), and who will be able to invoke the installed program (the last is useful only if you install the software as super user or root into a system folder). Press the button "Next":

and in the last window of the installer, press "Done" to exit:

Important note for those who are running Smart Card Shell 3 on RHEL9 (Rocky Linux 9, Alma Linux 9)!

Smart Card Shell 3 needs the library libpcsclite.so, but no package provides libpcsclite.so on RHEL9. To overcome that issue, install the package pcsc-lite-libs (if it is not already installed) and create the symlink /usr/lib64/libpcsclite.so that points to /usr/lib64/libpcsclite.so.1:

cd /usr/lib64
ln -s libpcsclite.so.1 libpcsclite.so

 

4. Running Smart Card Shell 3 GUI

Be sure the Smart Card Shell 3 GUI is installed. Expand the "Applications" menu (1), go to "Programming" (2), press there "Smart Card Shell 3" (3):

and wait for the appearance of the main window of the program:

During the first run, a new window might appear, asking for configuring the path to a working directory, where the output files will be stored by default. Click the "Browse" button:

select the folder (1) and press "Open" (2) to go back:

Thus path to the folder will appear in the text field (next to the "Browse" button). In addition, mark at least "Use this as the default and do not ask again", to complete the configuration and pressing "OK" to exit:

 

5. Loading the key manager in Smart Card Shell 3 GUI

Run Smart Card Shell 3 GUI. The key manager is a loadable script, dedicated to manage the objects in the token.

To load it, either expand "File" menu and select there "Key Manager":

or press "Ctrl+M". Once loaded, the key manager will check if the token is connected and will create in the main window a tree of those objects, it discovered in the token. Details about all important events will be reported in the "Shell" tab:

 

6. Initializing the token and configuring DKEK to enable the import of keys and X.509 certificates from PKCS#12 files

The goal of the initialization process, is to enable the import (export too) of keys and X.509 certificates, stored in files (most often PKCS#12 files), into the token, , based on "device-key-encryption-key" (DKEK) type of store. Note that DKEK is not enabled by default.

WARNING! DURING THE INITIALIZATION, ALL DATA, STORED IN THE TOKEN, WILL BE LOST!

To start with the initialization, run the Smart Card Shell 3, load the key manager script, click once with the right button of the mouse upon "SmartCard-HSM" (that is the root of the key manager tree), and select "Initialize Device" in the menu:

Supply the following information (or press "Cancel" to terminate the initialization):

  • The actual SO-PIN for configuring the token. The default SO-PIN code is 3537363231383830, unless it has been changed (if you forget the SO-PIN, consider the token lost). Press "OK" to continue:

  • The label of the token (that is the token's friendly name, displayed in the PKI applications). Press "OK" to continue:

  • The authentication mechanism for restricting the access to the objects and processor of the token. In most cases, you might need to select "User PIN" (you may set another authentication mechanism, but this one is the most poplar one). Press "OK" to continue:

  • The way to restore the access to the keys and X.509 certificates, if the PIN is lost, forgotten, or locked (if a wrong PIN is entered more than 3 times, consecutively). Select "Resetting PIN with SO-PIN allowed" and press "OK" (select "Resetting PIN with SO-PIN not allowed" only in specific cases, where the implementation of such policy is necessary):

  • The new PIN code (do not use the number shown in the picture bellow). Press "OK" to continue:

  • The new PIN code (again, for confirmation). Press "OK" to continue:

  • Request for using "DKEK Shares". Press "OK" to continue:

  • The number of DKEK shares (use 1, unless you are expert). Press "OK" to continue:

  • Press "Cancel" here (if you press "OK" both SO-PIN and PIN codes will be stored locally in an unencrypted file):

After the success of the initialization, you will see only three objects displayed in the key manager tree: User PIN, SO-PIN, and DKEK entry. The message "Initializing complete" (an indication that the requested initialization has been successfully completed) will be seen in the "Shell" tab:

Note, that at this point, the requested DKEK shares are not yet initialized or/and imported to the token! The appearance of "DKEK set-up in progress with 1 of 1 shares missing" in the key manager tree indicates that. You need to request manually the creation of DKEK shares file and import its content to the token, by following strictly the instructions given bellow:

  • Request the creation of DKEK share, by clicking once with the right button of the mouse on the root of the key manager tree (on "SmartCard-HSM) and picking "Create DKEK share" in the menu:

  • Enter the name of DKEK file to create, and press "OK" (store the file in the working directory of the program, configured during the first run):

  • Set the password for protecting the DKEK share file content and press "OK":

  • Confirm the password for protecting the DKEK share file content and press "OK":

  • With the left button of the mouse, click once upon the object named "DKEK set-up in progress with 1 of 1 shares missing", displayed in the key manager section of the main window of the program:

  • Use the button "Browse" to find and choose the created DKEK file (file extension is *.pbe), and press "OK":

  • Enter the password set (before) for protecting the content of the DKEK file:

It will take up to 10 seconds to derive the keys and import the DKEK into the token (watch the related messages, appearing in the "Shell" tab). At the end, you will see that the object "DKEK set-up in progress with 1 of 1 shares missing" (in the key manager tree) will be renamed (the new name will include the ID of the DKEK object):

IMPORTANT! At this point, you need to store a copy of the DKEK share file, generated during the initialization, in a safe place!

In the examples above, that file is /home/vesso/CardContact/2019_02.pdb, but in you case the file will be with different name and location.

 

7. Generating ECC key pair (by means of DKEK shares)

IMPORTANT! Be absolutely sure that no application, other than Smart Card Shell 3, is communicating with the token. Stop all running processes of PKCS#11 compatible software (like Mozilla Firefox, Mozilla Thunderbird, Google Chrome, XCA), that might take over the token.

Start the Smart Card Shell 3, plug the token into the USB port, and load the key manager script. Be sure that the token is initialized properly, to support DKEK shares.

Click once on the token name, in the key manager section, with the right button of the mouse and select "Generate ECC Key" in the menu:

Select the elliptic curve type, and press "OK":

Provide a friendly name (alias) for the key pair (it is an internal name for naming the key pair object in the token) and press "OK":

Type (separated by comma) the list of the hex codes of the signature algorithms, that will be allowed for the signing, when using the encryption key (the most commonly used ones, 73,74,75, are given in the example bellow), then press "OK":

Wait until the token is finishing with the generation of the requested key pair. Once ready, you will see the new key object under the tree of the DKEK share:

 

7. Importing key pair and the corresponding X.509 certificate from PKCS#12 file into the token (by means of DKEK shares)

IMPORTANT! Be absolutely sure that no application, other than Smart Card Shell 3, is communicating with the token. Stop all running processes of PKCS#11 compatible software (like Mozilla Firefox, Mozilla Thunderbird, Google Chrome, XCA), that might take over the token.

Otherwise the PKCS#12 import might fail, by rising (in the "Shell" tab) the following error:

GPError: Card (CARD_INVALID_SW/27010) - "Unexpected SW1/SW2=6982 (Checking error: Security condition not satisfied) received" in ...

Start the Smart Card Shell 3, plug the token into the USB port, and load the key manager script. Be sure that the token is initialized properly, to support DKEK shares. Using DKEK share in this case is mandatory for this operation.

  • Click once on the token name in the key manager section, with the right button of the mouse, and select "Import from PKCS#12" in the menu:

  • Specify the number of DKEK shares to use (use 1, if you follow the recipes provided in this document), and click "OK":

  • Select the file, containing the DKEK shares (use the file name created during the initialization), and click "OK":

  • Enter the password for decrypting the DKEK file (that password is set during the creation of the file), click "OK", and wait up to 10 seconds for generating the shared keys:

  • Select the PKCS#12 file and click "OK":

  • Provide the password, set for protecting the content of the PKCS#12 file, and click "OK":

  • Select the key pair and X.509 certificate to import from the PKCS#12 file, by choosing their internal PKCS#12 name, and click "OK":

  • Enter a name to assign to the imported key pair and X.509 certificate, and click "OK":

  • Click "OK" if you wanna import more key pairs and X.509 certificates, stored in the same PKCS#12 file, or click "Cancel" to finish:

If the import is successful, you will see the key pair imported into the DKEK share (in the key manager section), and information about the process, in the "Shell" section (as shown in the red frames bellow):

IMPORTANT! You cannot import X.509 certificate chain from a PKCS#12 container into the token, by using the procedure proposed above.

But you might do that later, by using pkcs11-tool, it that is really necessary. Notice, that the X.509 certificates in the chain are public information and they might be used in out-of-the-box manner (installed in the software certificate repository of the browser, which will be using with the token). Their presence in the token storage is not mandatory.


Using SmartCard-HSM 4K USB-Token to work with ECDSA keys in RHEL, CentOS, and Enterprise Linux, versions 7 and 8

Content:

1. Introduction

2. Connecting the device

3. Downloading, compiling, and installing the last stable release of OpenSC and HSM code

4. Initializing the device (setting the PINs)

5. Generating 521-bit EC key pair

6. Using the USB token as OpenSSL PKCS#11 engine

7. Generating CSR, based on a key pair previously stored in the token, through OpenSSL PKCS#11 engine

8. Importing X.509 certificate to the token storage

 

1. Introduction

In the modern cryptographic systems, the use of Elliptic Curve cryptography (ECC) becomes de facto a standard. Meanwhile, even now (it is 2019), it is quite rare to find a cryptographic token that supports the generation and use of ECDSA keys, up to 512 bits, SHA512 hash function (embedded in the processor of the token), and comes with a driver for Linux OS support. Most of the available tokens support mostly RSA key pairs, and even if they support ECDSA, that support is partial and the maximum key size is limited bellow 512 bits.

Surprisingly, you can find a reliable crypto token, that supports ECDSA 512-bit keys and SHA512 at:

cardomatic.de

The SmartCard-HSM 4K USB-Token, they have in sale, is supported by the driver library libccid.so, which is part of the OpenSC package (version 0.16 or higher). If one can download, compile, and install locally both the latest OpenSC and HSM code release, that is sufficient to employ the SmartCard-HSM 4K USB-Token in OpenSSL (as an engine), Mozilla Firefox, and Mozilla Thunderbird (as a security device).

The notes given bellow explain how to make the SmartCard-HSM 4K USB-Token device available in a Linux-based system running CentOS 7, Scientific Linux 7, Red Hat Enterprise Linux 8, and (possibly) Red Hat Enterprise Linux 8, how initializing the device, and the modules to interact the opensc tools (like pkcs11-tools and pkcs15-tools).

 

2. Connecting the device

Install the following packages (there is a good chance they are already installed):

# yum install pcsc pcsc-lite-ccid opensc

Enable the daemon pcscd to be loaded when starting/restarting the system:

# systemctl enable pcscd

and run it manually afterwards:

# systemctl start pcscd

Now you can connect the SmartCard-HSM 4K USB-Token device to the system. Records like those given bellow will be added to the /var/log/messages by syslog:

May 10 15:00:06 argus kernel: usb 3-10: new full-speed USB device number 9 using xhci_hcd
May 10 15:00:06 argus kernel: usb 3-10: New USB device found, idVendor=04e6, idProduct=5816
May 10 15:00:06 argus kernel: usb 3-10: New USB device strings: Mfr=1, Product=2, SerialNumber=5
May 10 15:00:06 argus kernel: usb 3-10: Product: uTrust 3512 SAM slot Token
May 10 15:00:06 argus kernel: usb 3-10: Manufacturer: Identiv
May 10 15:00:06 argus kernel: usb 3-10: SerialNumber: 55511247701280

Their appearance there does not exactly mean the device is accessible by the applications. It only indicates that the USB device is properly recognized by libusb. In addition, the device will appear under the Vendor Name: SCM Microsystems, Inc., Vendor ID: 04e6, and Product ID: 5816, in the output generated by the execution of lsusb:

Bus 003 Device 009: ID 04e6:5816 SCM Microsystems, Inc.

If detailed debugging information, regarding the process of device detection, performed by pcscd daemon, is required, do modify the content of the file /usr/lib/systemd/system/pcscd.service (used by systemd to invoke the daemon pcscd), by adding the additional declaration --debug to the end of the line starting with "ExecStart":

ExecStart=/usr/sbin/pcscd --foreground --auto-exit --debug

Save the changes to the file, load the new list of declarations:

# systemctl daemon-reload

and finally restart the daemon pcscd:

# systemctl restart pcscd

At that moment, start monitoring the new content appended to the file /var/log/messages (# tailf /var/log/messages will do), then unplug and plug in the device, and watch what kind of messages the syslog daemon is appending to the file.

To prevent the fast growth of the /var/log/messages size on the disk, immediately after finishing with the analysis of the debug information, do restore the original declarations in /usr/lib/systemd/system/pcscd.service (remove the additional declaration --debug), reload it, and restart the daemon pcscd!

 

3. Downloading, compiling, and installing the last stable release of OpenSC and HSM code

First, install the required RPM packages (if they are not already installed):

# yum install git gcc gcc-c++ make

Then fetch the code of sc-hsm-embedded project, hosted on Github, configure, compile, and install it (change the destination folder after --prefix, if needed):

$ git clone https://github.com/CardContact/sc-hsm-embedded.git
$ cd sc-hsm-embedded
$ ./configure --prefix=/usr/local/sc-hsm-embedded
$ make
$ sudo make install

General note: Red Hat Enterprise Linux 8 (as well as CentOS 8 and Scientific Linux 8), ships OpenSC version 0.19. That means one does not need to compile OpenSC code, as explained bellow, in systems running EL8.

Once the installation is successfully completed, download, compile, and install the latest stable release of the OpenSC code (change the destination folder after --prefix and --with-completiondir, if needed):

$ wget https://github.com/OpenSC/OpenSC/releases/download/0.19.0/opensc-0.19.0.tar.gz
$ tar xvf opensc-0.19.0.tar.gz
$ cd opensc-0.19.0
$ ./configure --prefix=/usr/local/opensc-0.19.0 --with-completiondir=/usr/local/opensc-0.19.0/share/bash-completion/completions
$ make
$ sudo make install

The next step is to add the folders containing the installed binaries and libraries to the user's PATH and LD_LIBRARY_PATH environmental variables. Those additions can be made either system-wide (available to all users, inclusive) or user-specific (available only to specific users, exclusive):

  • system-wide:

    Write down the following export declarations:

    export PATH=/usr/local/opensc-0.19.0/bin:$PATH
    export LD_LIBRARY_PATH=/usr/local/sc-hsm-embedded/lib:/usr/local/opensc-0.19.0/lib:$LD_LIBRARY_PATH

    to the file /etc/profile.d/opensc.sh (create the file, it does not exist by default there).

  • user-specific:

    Open each ~/.bashrc file and append (to the end) the following lines:

    export PATH=/usr/local/opensc-0.19.0/bin:$PATH
    export LD_LIBRARY_PATH=/usr/local/sc-hsm-embedded/lib:/usr/local/opensc-0.19.0/lib:$LD_LIBRARY_PATH

 

4. Initializing the device (setting the PINs)

The SmartCard-HSM 4K USB-Token device comes uninitialized! That means the device cannot be used, unless complete the initialization process first.

Connect the token to the system and invoke the tool sc-hsm-tool by specifying the SO PIN (SO stands for "Security Officer", change SO PIN 3537363231383830, specified in the example bellow, with another unique 16-digit long decimal number and do not forget it) and the user's PIN (change 123456 to another number):

$ sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 123456

Here, the number after --so-pin is the SO PIN and the one after --pin is the user's PIN. Note that the SO PIN is the most important PIN, for it allows write access to the all slots of the device storage. Also, it can change every PUK and PIN, previously stored there (that includes the SO PIN itself). So do not loose SO PIN number!


5. Generating 521-bit EC key pair

Invoke the tool pkcs11-tool and specify the key type (EC:specp521r1 for 521-bit EC encryption key) and key pair ID label (it helps later to access the keys):

$ pkcs11-tool --module libsc-hsm-pkcs11.so -l --keypairgen --key-type EC:secp521r1 --id 10 --label "EC pair ID 10"

The user's PIN will be requested next, to grant access to the device storage and processor:

Enter PKCS#11 token PIN for SmartCard-HSM:

If the provided user's PIN is correct, it will take up to 2-3 seconds to execute and complete the key generation process.

The most important part of the command line above is the ID number assigned to the key pair (given above is 10, but you may reserve some other number, including hexadecimal number syntax, which is not already taken), because from that moment onward, the keys of that pair can be selected and involved in operations only if their ID number is specified.

 

6. Using the USB token as OpenSSL PKCS#11 engine

Install the package openssl-pkcs11 to enable the OpenSSL PKCS#11 engines functionality:

# yum install openssl-pkcs11

After that, store the following minimal OpenSSL configuration into a local file (openssl_hsm.cnf, for the sake of our illustration process):

openssl_conf = openssl_def

[openssl_def]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = libsc-hsm-pkcs11
dynamic_path = /usr/lib64/engines-1.1/pkcs11.so
MODULE_PATH = /usr/local/opensc-0.19.0/lib/libsc-hsm-pkcs11.so
init = 0


[ req ]
distinguished_name      = req_distinguished_name
string_mask = utf8only

[ req_distinguished_name ]

The only declaration in openssl_hsm.cnf one might need to change is that of MODULE_PATH:

MODULE_PATH = /usr/local/opensc-0.19.0/lib/libsc-hsm-pkcs11.so

Replace /usr/local/opensc-0.19.0 there with the actual folder, where the file libsc-hsm-pkcs11.so is stored. Note that the file is brought there during the installation of the HSM code).

 

7. Generating CSR, based on a key pair previously stored in the token, through OpenSSL PKCS#11 engine

If the OpenSSL PKCS#11 engine configuration file is available, the generation of CSR PKCS#10 block requires to specify the key pair ID (that is the number assigned to the key pair during the process of key pair generation):

$ openssl req -new -subj "/CN=server.example.com" -out request.pem -sha512 -config openssl_hsm.cnf -engine pkcs11 -keyform engine -key 10

One can expand both command line arguments and the set of declarations stored in openssl_hsm.cnf, if the CSR should contain some specific extensions, requested by the certificate issuer.

 

8. Importing X.509 certificate to the token storage

That type of operation is possible only if the X.509 certificate is stored in DER format (binary). For example, if the file SU_ECC_Root_CA.crt contains PEM formatted X.509 certificate, that certificate might be converted into DER format, by using openssl:

$ openssl x509 -in SU_ECC_Root_CA.crt -outform DER -out SU_ECC_Root_CA.der

To import the DER formatted X.509 certificate to the USB storage token, use the tool pkcs11-tool:

$ pkcs11-tool --module ibsc-hsm-pkcs11.so --login --write-object SU_ECC_Root_CA.der --type cert --id `uuidgen | tr -d -` --label "SU_ECC_ROOT_CA"

The label string after --label, naming the X.509 certificate, should be specified in a way hinting the purpose of having and using that certificate.


Using ECC keys with NetworkManager for EAP-TLS authentication

Content:

1. Introduction

2. Description of the problem

3. Cause and solution

Appendix: How to create PKCS#12 file using OpenSSL


1. Introduction

NetworkManager is employed by almost all modern Linux distributions to manage a large variety of network connection types (Ethernet, WiFi, VPN, PPP) and has got both GUI (graphical user interface) and command line tools.

NetworkManager can read PEM-formatted RSA end-user certificates and keys, when a 802.1x-based WiFi connection requires the user authentication process to be based on Extensible Authentication Protocol (EAP) with Transport Layer Security (TLS) - EAP-TLS, defined in RFC5216. For example, the command line:

nmcli connection add type wifi con-name "eduroam" ifname wlan0 ssid "eduroam" -- wifi-sec.key-mgmt wpa-eap 802-1x.eap tls 802-1x.ca-cert /home/username/eduroam/ecc_ca.crt 802-1x.identity username@example.com 802-1x.phase2-ca-path /home/username/eduroam/ca.crt  802-1x.client-cert /home/username/end_user.crt 802-1x.private-key /home/username/end_user.key 802-1x.phase2-private-key-password "some_password" 802-1x.anonymous-identity "anonymous@example.com"

defines a new WiFi connection, manageable by NetworkManager, if the file /home/username/rsa_end_user.key contains PEM-formatted RSA (usually encrypted) private key that is complementary to the public key in /home/username/rsa_end_user.crt.


2. Description of the problem

When the key file, given after 802-1x.private-key, contains PEM-formatted private key generated using Elliptic-Curves, the NetworkManager fails to parse it and rises the following error message:

Error: failed to modify 802-1x.private-key: 802-1x.private-key: invalid private key.

3. Cause and solution

The construction of the PEM-formatted block, used for storing the private keys in text files, in case of RSA key:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,CA02E2DB3CA8464D0A35527EAE024204

...
-----END RSA PRIVATE KEY-----

is completely different from the one specific to the EC keys:

-----BEGIN EC PARAMETERS-----
...
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----

Handling that kind of differences, requires the implementation of a complex text parser, which might become (in certain cases) a source of problems (parsing text files to match patterns is always a challenge). Instead of updating the text parser, NetworkManager team decided to unify and optimize the process of certificate/key reading. To introduce more flexible and robust procedure for reading and identifying cryptography objects, and to simplify the programming code, NetworkManager team adopted a PKCS#12 containers reader. The goal of PKCS#12 is to provide the software applications with a container format for storing (binary) cryptography objects, like keys and certificates (incl. chain of certificates). Having PKCS#12 functionality added to the programming code not only shortens that code, but also makes the process of reading, identifying, and verifying the cryptography objects a task easy to perform (at the expense of linking the executable to external libraries like OpenSSL and NSS libraries).

To solve the problem described above, the end user certificate and key need to be converted and stored into a single PKCS#12 file (with extension *.p12). Then, when invoking nmcli to create the new WiFi connection set of settings, that file (as full path) should be given after the switches 802-1x.client-cert and 802-1x.private-key:

nmcli connection add type wifi con-name "eduroam" ifname wlan0 ssid "eduroam" -- wifi-sec.key-mgmt wpa-eap 802-1x.eap tls 802-1x.ca-cert /home/username/eduroam/ecc_ca.crt 802-1x.identity username@example.com 802-1x.phase2-ca-path /home/username/eduroam/ca.crt  802-1x.client-cert /home/username/rsa_end_user.p12 802-1x.private-key /home/username/rsa_end_user.p12 802-1x.phase2-private-key-password "some_password" 802-1x.anonymous-identity "anonymous@example.com"

Short and useful recipe for creating PKCS#12 files is given in "Appendix" down bellow.


Appendix: How to create PKCS#12 file using OpenSSL

openssl pkcs12 -export -aes256 -maciter -in end_user.crt -inkey end_user.key -name "ECC_End_User" -chain -CAfile ca.crt -out end_user.p12

Lightweight parser for locating entries in the FreeRADIUS log files by MAC address

The goal of developing and supporting this parser script, is to help analyzing the log files mainainned by the FreeRADIUS daemon radiusd (the content of those files is in plain text). When analyzing those files, the script is parsing their content line by line, and conditionally performing an additional check, if the line content has pattern mathching the one typical for the WiFi clients' autnetnication requests. That additional check has a goal to check if the MAC address of the client's WiFi adaper matches the one passed to the script as an invoking parameter. If match is found, the script prints the line to the standard output.

The script might be of help to the administrators of the FreeRADIUS servers that are part of the Eduroam infrastructure. Its code could be modified to support specific tasks like grouping the entries in the log files or providing front end to Zabbix agents.

You can get the code of the script and more information at:

https://github.com/vessokolev/radius_log_parser


IMAP connector for FreeRADIUS to support EAP-TTLS authentication in Eduroam

Content:

  1. Introduction
  2. The code of the IMAP connector
  3. Configuring FreeRADIUS to use the IMAP connector
  4. SELinux issues
  5. Notes on the productivity

1. Introduction

In spite its amazing collection of drivers supporting a variety of authentication protocols, FreeRADIUS does not support (yet) verification of the user names and passwords against IMAP/IMAPS servers, especially when using EAP-TTLS method for authenticating the users. It is also true that in average the IMAP servers are slow authenticators, compared to those based on LDAP or Active Directory, which might explain the lack of interest among the developers to create an intrinsic IMAP authentication module and include it into the FreeRADIUS source code. Nevertheless, there are cases when one simply cannot obtain direct access to the authentication data base, and in that case the only possibility available is to authenticate the users of the RADIUS server against publicly available service, like IMAP.

But why the IMAP authentication is considered slow? The goal of the IMAP servers is to provide access to the user's e-mail storage. In that aspect they are more closer to the file serversm then to the dedicated authentication servers (like 389 Directory Server). In other words, the major aim of developing IMAP server code is not to handle fast authentication of intensive stream of authentication requests. But if the intensity of incoming authentication requests is not huge, and the IMAP server is not engaged into intensive operations for managing the mail box content, it might be possible to relay on that server to handle a moderate stream of authentication request, sent by one or more FreeRADIUS servers.

One might find on Internet some solutions connecting the FreeRADIUS authentication process to IMAP server indirectly, through Linux Pluggable Authentication Modules (PAM). That way the FreeRADIUS server deals with local (to the Linux system hosting the server) users. Once sent to the PAM, the authentication request is passed to a specific PAM library, configured to connect to the IMAP server. In turn, the library passes the user name and password combination to the IMAP server for a verification. That kind of authentication process seems clear and simple, but it turns the remote users into local to the Linux system running the RADIUS server. In certain cases that might open an exploitable hole in the system security.

Creating an external IMAP connector - an application or script that can be invoked by the FreeRADIUS server process on demand - seems a way more elegant and secure method for verifying the user name and password pairs against external IMAP servers. Especially, if the connector code is based on a set of software components, that can be installed and kept updated by using the Linux distribution package management system. One such set of software components is Python and its modules, because: (1) every modern Linux distribution have its own optimized and supported (via updates) Python packages, and (2) it is easy and simple to write a Python code that established and manages connections to IMAP servers, by means of intrinsic modules (like imaplib and ssl). The connector (regardless the programming language) need to receive at least the user name and password, as invoking parameters, and return back an exit status value (return value) on completion. If that value is zero, the FreeRADIUS sever process considers the user credentials verified.

Given bellow is a simple Python script, behaving as IMAP connector.

2. The code of the IMAP connector

Provided bellow is a Python 3 code, based on the modules imaplib, sys, and ssl, all intrinsic to the Python distribution included in CentOS distribution (check if the Python package in your distribution does not include imaplib, which is unlikely):

#!/usr/bin/env python3

import imaplib
import ssl
import sys

if len(sys.argv) == 3:

    hostname = 'imap.example.com'

    context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

    context.options |= ssl.OP_NO_SSLv2
    context.options |= ssl.OP_NO_SSLv3

    context.set_ciphers('EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:' + \
                        'EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:' + \
                        'EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:' + \
                        'DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:' + \
                        '!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS')

    context.verify_mode = ssl.CERT_REQUIRED
    context.check_hostname = True
    context.load_verify_locations("/etc/pki/tls/certs/ca-bundle.crt")

    try:
        imap_obj =  imaplib.IMAP4_SSL(hostname, 993, ssl_context = context)
    except:
        sys.exit(1)

    try:
        status = imap_obj.login(sys.argv[1], sys.argv[2])
    except:
        sys.exit(1)

The code establishes a SSL session (using TLSv1.2 protocol) to the IMAP server with host name imap.example.com (change it to that of your IMAP server), and thus checks the user credentials (the user name is assigned to sys.argv[1], the password is the value of sys.argv[2]). One might edit the list of ciphers in context.set_ciphers, if that is necessary, following the OpenSSL syntax for selecting ciphers.

If IP address is required instead of fully qualified host name (not recommended), the value of context.check_hostname have to be set False.

The file /etc/pki/tls/certs/ca-bundle.crt is the standard bundle file containing copies of the most used and trusted CA certificates (it is maintained by the vendor of the Linux distribution). That file is part of the package ca-certificates, installed by default in CentOS 7. That file might have different name and path in other distribution. Note, that if the X.509 certificate of the IMAP server is signed by some local certificate authority, whose CA certificate is not included in the list of CA certificates provided by the vendor of the Linux distribution, that particular CA certificate can be stored in a file alone. Then the file path and name should be declared an argument of context.load_verify_locations.

3. Configuring FreeRADIUS to use the IMAP connector

Before starting, do save the script given above as /var/lib/radiusd/login_imap.py.

To terminate the TLS tunnel, decrypt its content, and authenticate the users with realm (domain) "wifi.example.com" locally, the following configuration should be included to the file /etc/raddb/proxy.conf:

realm "wifi.example.com" {
   type = radius
   authhost = LOCAL
   accthost = LOCAL
}

To set PAP as default authentication protocol (after executing the EAP part of the authentication process), create the following entry inside the file /etc/raddb/users:

DEFAULT  Auth-Type = PAP

Then open the file /etc/raddb/modules/pap and add there the configuration section:

exec papauth {
     wait = yes
     program = "/var/lib/radiusd/login_imap.py '%{Stripped-User-Name}' '%{User-Password}'"
     input_pairs = request
     output_pairs = config
     }

If the IMAP server accepts e-mail addresses as user names, replace there %{Stripped-User-Name} with %{User-Name}.

Finally, open the file /etc/raddb/sites-available/inner-tunnel, go to the authenticate section there and change the declaration:

        Auth-Type PAP {
                pap
        }

into:

        Auth-Type PAP {
                papauth
        }

Why does the script check the number of elements in sys.argv list? It is because radiusd invokes the script twice for every single user authentication and therefore some polymorphic code is required to treat each call differently. The first time, the script is invoked, is right after the TLS tunnel is established. In this case the goal is to check the real user name and password against the specified IMAP server. If radiusd is running in debug mode (as radiusd -X), the following messages, related to the first call, will appear:

# Executing group from file /etc/raddb/sites-enabled/inner-tunnel
+group PAP {
[papauth]  expand: %{Stripped-User-Name} -> username
[papauth]  expand: %{User-Password} -> userpassword

Note that only two actual parameters are passed to the script by radiusd. Nevertheless, the result is the Python list sys.argv that contains three elements. The first element (sys.argv[0]) is the path to the script file, known to the radiusd (following the configuration above that should be /var/lib/radiusd/login_imap.py), and its value is assigned implicitly by the Python interpreter, the second one (sys.argv[1]) is the value of %{Stripped-User-Name}, and the third element (sys.argv[2]) is the password (that is the value of %{User-Password}). Therefore, sys.argv of this length will trigger the execution of the IMAP authentication section in the Python code. Otherwise, the script will return exit status 0 regardless the number of elements in sys.argv. The last is used to complete the authentication when radiusd is following the instructions found in the post-auth section located inside /etc/raddb/sites-enabled/default. In debug mode (radiusd) the following sequence of messages, related to the post-auth instructions, will be displayed on the screen:

# Executing section post-auth from file /etc/raddb/sites-enabled/default
+group post-auth {
[exec]  expand: %{Stripped-User-Name} -> anonymous
[exec]  expand: %{User-Password} ->
[exec]  expand: %{Calling-Station-Id} -> 02-00-00-00-00-01
[exec]  expand: %{NAS-IP-Address} -> 127.0.0.1
[exec]  expand: %{Framed-Protocol} ->

From those messages, it becomes clear that during that second execution of the script, the number of input parameters to the script is greater than two (unless there is some specific FreeRADIUS configuration, that reduces that number down to two). Therefore, the Python interpreter will not execute the IMAP authentication section in the script and will send back to radiusd an exit status 0.

4. SELinux issues

The radiusd expects the SELinux context of the IMAP connector script /var/lib/radiusd/login_imap.py to be the one of radiusd_t. That kind of context cannot be assigned by using chcon (at the present) and therefore radiusd cannot invoke the script. The only way to solve this issue is to create a specific SELinux module and install it. Srart radiusd and try to authenticate an user (if SELinux is enforced the authentication will fail). Then find the following type of entries in /var/log/audit/audit.log:

type=AVC msg=audit(1536040511.292:21627): avc:  denied  { execute } for  pid=29569 comm="radiusd" name="login_imap.py" dev=sda3 ino=132112 scontext=unconfined_u:system_r:radiusd_t:s0 tcontext=unconfined_u:object_r:radiusd_var_lib_t:s0 tclass=file
type=AVC msg=audit(1536040931.979:21649): avc:  denied  { execute_no_trans } for  pid=29739 comm="radiusd" path="/var/lib/radiusd/login_imap.py" dev=sda3 ino=132112 scontext=unconfined_u:system_r:radiusd_t:s0 tcontext=unconfined_u:object_r:radiusd_var_lib_t:s0 tclass=file
type=AVC msg=audit(1536041114.006:21653): avc:  denied  { name_connect } for  pid=29802 comm="python" dest=143 scontext=unconfined_u:system_r:radiusd_t:s0 tcontext=system_u:object_r:pop_port_t:s0 tclass=tcp_socket

and save them in a file (the file name myradius.avc is adopted in the example bellow). Finally, generate and then install the custom SELinux module:

# audit2allow -a -M myradius < myradius.avc
# semodule -i myradius.pp

5. Notes on the productivity

Establishing and supporting high number of simultaneous IMAP over SSL sessions, might bring a significant latency to the authentication process. One possible way to reduce the latency is to adopt an external SSL wrapper (like stunnel) to connect the radius server host to the IMAP server, and use a modification of the connector script, based on plain IMAP sessions to localhost:

#!/usr/bin/env python3

import imaplib
import sys

if len(sys.argv) == 3:

    hostname = 'localhost'

    try:
        imap_obj = imaplib.IMAP4(hostname)
    except:
        sys.exit(1)

    try:
        status = imap_obj.login(sys.argv[1], sys.argv[2])
    except:
        sys.exit(1)

Using nmcli to create 802.1x EAP-TTLS connections

The GUI of NetworkManager is pretty user friendly, when it comes to create easily 802.1x connection configurations (WPA2 Enterprise). In a command line environment (non-GUI setups) that kind of connections should be created and handled by using the TUI tool nmcli. When invoked, that tool communicates with the locally running NetworkManager daemon.

It is rather strange that on many Internet user forums an easy thing to do, like creating and exploring 802.1x connection by using nmcli, is declared mission impossible, and wpa_supplicant is pointed out as the only available tool for connecting to WPA2 Enterprise hotspot infrastructure. The goal of this post is to show that nmcli is capable of doing that natively.

To create 802.1x connection in command line mode the nmcli tool need to be invoked correctly. It is not practical to enter the nmcli interactive shell for describing the connection parameters one by one. The easiest way is to create the connection description at once by executing a single command line. Note that some of the options passed as arguments to nmcli are in fact critical, even if they are not considered as such by the syntax checker. For instance, the process of tunnelling the plain-text password requires a positive verification of the RADIUS X.509 certificate to resist the mighty "man-in-the-middle" kind of attacks. Therefore, a copy of the CA X.509 certificate need to be stored locally, as text file (preferably in PEM format).

The example bellow shows how to define all the parameters of a 802.1x connection, required for using "eduroam" hotspot (more about Eduroam):

$ sudo nmcli connection add type wifi con-name "eduroam" ifname wlan0 ssid "eduroam" -- wifi-sec.key-mgmt wpa-eap 802-1x.eap ttls 802-1x.phase2-auth pap 802-1x.identity "user@some.edu" 802-1x.anonymous-identity "anon@some.edu" 802-1x.ca-cert "/home/user/CA-wifi.crt" 802-1x.password 3423sd3easd32e2

Note the use of full path to the CA X.509 certificate file given above (/home/user/CA-wifi.crt). Declaring a relative path instead need to be avoided.

In case of a successful execution of the command line, the connection "eduroam" will appear as available in the list of suported connections:

$ nmcli c s

Once listed there, the connection can be activated by executing:

$ sudo nmcli c up eduroam

and in case of successful activation, the usual kind of message will appear on the display:

Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/9)

It is very good idea to clear the shell history in order to prevent the password from disclosure, since it is part of the command line defining the connection.

The example given above has been tested on the latest CentOS 7, Red Hat Enterprise Linux 7, Scientific Linux 7, and Ubuntu 18.04.1 LTS.


Creative Commons - Attribution 2.5 Generic. Powered by Blogger.

Implementing LUKS Encryption on Software RAID Arrays with LVM2 Management

A comprehensive guide to partition-level encryption for maximum security ...

Search This Blog

Translate