# Client SSL Certificate on Linux: Chrome, Chromium, Firefox


<!--more-->

This guide continues the article
[Configuring Client Certificate Authentication on Nginx]({{< relref "client-certificate-authentication-nginx" >}}).
You have a `user1.p12` file with the certificate and private key, and its password. Now it needs to be installed in
the browser.

Unlike Windows or macOS, Linux has no shared system store for client certificates. Each application uses its own
**NSS Shared Database**:

| Browser | Where certificates are stored |
|---|---|
| Chrome, Chromium, Opera, Brave, Vivaldi, Edge | shared user database `$HOME/.pki/nssdb` |
| Chromium from Snap | `$HOME/snap/chromium/current/.pki/nssdb` |
| Flatpak browsers | `$HOME/.var/app/<app id>/.pki/nssdb` |
| Firefox | its own database in the profile directory |

So Chromium-based browsers need to be set up once, and Firefox separately.


## Chrome, Chromium and other Chromium-based browsers

### Using the browser UI

1. Open **Settings → Privacy and security → Security → Manage certificates**
   (or type `chrome://certificate-manager` in the address bar).
2. Go to **Your certificates** (in older versions, the **Your certificates** tab of the **Manage certificates**
   dialog).
3. Click **Import**, select `user1.p12` and enter its password.

The certificate appears in the list. Restart the browser to make sure it picks up the change, then open the site.
The browser will ask you to choose a certificate; pick the one you installed.

### From the command line

You need the NSS tools package. On Debian/Ubuntu/Mint:

```shell
sudo apt update
sudo apt install libnss3-tools
```

On Fedora/CentOS/RHEL:

```shell
sudo dnf install nss-tools
```

On Arch Linux the tools are part of the `nss` package.

If the database does not exist yet (the browser has never been started), create it:

```shell
mkdir -p $HOME/.pki/nssdb
certutil -d sql:$HOME/.pki/nssdb -N --empty-password
```

Import the **PKCS#12** certificate from a `.p12` or `.pfx` file. The tool will ask for the file password:

```shell
pk12util -d sql:$HOME/.pki/nssdb -i user1.p12
```

List installed certificates (**-L**) and private keys (**-K**):

```shell
certutil -d sql:$HOME/.pki/nssdb -L
certutil -d sql:$HOME/.pki/nssdb -K
```

Delete a certificate together with its private key. Take the certificate name from the `certutil -L` output:

```shell
certutil -d sql:$HOME/.pki/nssdb -F -n "Certificate Name"
```

For Chromium from Snap or Flatpak browsers, use the database path from the table above.


## Firefox

### Using the browser UI

1. Open the menu and choose **Settings**.
2. Go to **Privacy & Security**, find the **Certificates** section and click **View Certificates...**
   You can also open `about:preferences#privacy` directly.
3. On the **Your Certificates** tab click **Import...**, select `user1.p12` and enter its password.

The certificate appears in the list. On the first visit to the site Firefox asks which certificate to use. If you
check **Remember this decision**, the choice is saved on the **Authentication Decisions** tab, where it can also be
reset.

### From the command line

Firefox uses the same NSS database format, so the `libnss3-tools` / `nss-tools` utilities work here too. You only
need the profile directory. Find it on the `about:profiles` page: the **Root Directory** line of the default profile.
Usually it is:

- `$HOME/.mozilla/firefox/xxxxxxxx.default-release` for Firefox from distribution packages or from Mozilla;
- `$HOME/snap/firefox/common/.mozilla/firefox/xxxxxxxx.default` for Firefox from Snap (the default on Ubuntu);
- `$HOME/.var/app/org.mozilla.firefox/.mozilla/firefox/xxxxxxxx.default-release` for Firefox from Flatpak.

Close Firefox before importing so that it does not hold the database open.

```shell
PROFILE=$HOME/.mozilla/firefox/xxxxxxxx.default-release
pk12util -d sql:$PROFILE -i user1.p12
certutil -d sql:$PROFILE -L
```

If the Firefox database has a Primary Password, `pk12util` asks for it first and then for the `.p12` password.

Deleting works the same way as for Chromium:

```shell
certutil -d sql:$PROFILE -F -n "Certificate Name"
```


## Troubleshooting

- **The browser does not offer a certificate.** Check that the certificate is signed by the CA set in
  `ssl_client_certificate` in the nginx configuration, and that the CA and the client have different
  **Organization Name** fields.
- **The wrong certificate was selected.** Chromium remembers the choice until the browser restarts, so close all its
  windows. In Firefox, remove the entry on the **Authentication Decisions** tab.
- **Password error on import.** Make sure the password is correct. If the file was created by a very old OpenSSL
  version with outdated algorithms, recreate it with a current version.
- **Checking without a browser.** If `curl --cert user1.crt --key user1.key https://example.com` works but the
  browser does not, the problem is in the certificate installation, not in the server configuration.

Guides for other systems:
[Windows]({{< relref "client-certificate-windows" >}}),
[macOS]({{< relref "client-certificate-macos" >}}),
[Android and iOS]({{< relref "client-certificate-android-ios" >}}).

