red

Getting a card to work.

No card detected · browser detecting…

Back to sign in

What this browser sent

Subject
Issuer
VerifiedNONE
Serial

Empty means the browser offered nothing at all, which is the same answer whether there is no reader, an empty reader, or a prompt that was dismissed - nothing here can tell those apart. Work through the steps below. Verification is chain-only; revocation is deliberately not checked, because the card points at revocation services this environment cannot reach and turning it on would fail every login for the wrong reason.

Set up a smartcard on Linux

Distribution:

1 · Card stack

sudo apt install -y opensc pcscd pcsc-tools libnss3-tools
sudo systemctl enable --now pcscd

Check the card is readable before blaming the browser:

opensc-tool --list-readers
opensc-tool --name              # e.g. Gemalto IDPrime 940
pkcs15-tool --list-certificates

Run these in your local desktop session. Over SSH you will get SCardEstablishContext: Access denied and the module will report “no slots attached” — pcscd only serves the active local session, so a remote shell makes a perfectly good reader look broken.

2 · Tell the browser about the card

Firefox keeps its own PKCS#11 store per profile:

modutil -dbdir sql:$HOME/.mozilla/firefox/*.default* \
  -add "OpenSC" -libfile /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so

Two things bite here.
SEC_ERROR_BAD_DATABASE usually means the profile does not exist yet — the *.default* glob matched nothing. Start Firefox once, close it, retry.
And if Firefox came from snap its profile lives under ~/snap/firefox/common/.mozilla/firefox/ — but it still will not work, because a confined snap cannot reach pcscd at all. Use the .deb from Mozilla's apt repository, or use Chrome.

Chrome / Chromium has no “load module” dialog on Linux. It reads the shared NSS database in your home directory, so the module goes there:

# check first - if OpenSC is already listed, skip the add
modutil -dbdir sql:$HOME/.pki/nssdb -list

# first time only, if the database does not exist yet
mkdir -p $HOME/.pki/nssdb && certutil -d sql:$HOME/.pki/nssdb -N --empty-password

modutil -dbdir sql:$HOME/.pki/nssdb -add "OpenSC" \
  -libfile /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so

# download the CA before importing it - certutil reads a local file
curl -k -o /tmp/red-mock-root.crt https://51-15-197-131.sslip.io/red-mock-root.crt
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "red mock root" -i /tmp/red-mock-root.crt

Verify with modutil -dbdir sql:$HOME/.pki/nssdb -list. Seeing “Failed to add module … Failure to load dynamic library” while the module is nonetheless listed as status: loaded means it was already added — check the list before assuming it failed. Chrome must be fully closed (chrome://restart) to pick it up, and snap/flatpak Chrome hits the same pcscd confinement as the Firefox snap.

If certutil asks for a Password or Pin for “NSS Certificate DB” and you never set one, press Enter — it is empty by default. Typing a value there sets a database password, and Chrome will prompt for it from then on. Undo with certutil -d sql:$HOME/.pki/nssdb -W and leave the new password blank.

2b · If the browser still does not offer the card

Everything can be correct — reader detected, module loaded, certificates visible to certutil -L -h all — and the browser still sends nothing, because choosing a certificate is a separate decision from being able to see one. Chrome can be told to pick it automatically for this site:

sudo mkdir -p /etc/opt/chrome/policies/managed
sudo tee /etc/opt/chrome/policies/managed/red-cardauth.json >/dev/null <<'JSON'
{
  "AutoSelectCertificateForUrls": [
    "{\"pattern\":\"https://51-15-197-131.sslip.io\",\"filter\":{\"ISSUER\":{\"CN\":\"Swedish Public Sector Person 2 CA v1\"}}}"
  ]
}
JSON

Chromium reads the same file under /etc/chromium/policies/managed/. Confirm it loaded at chrome://policy, then fully restart the browser. The filter matches on the card issuer, so the signing certificate on the same card is not offered by mistake.

Start the browser from your desktop, not over SSH and not from a systemd unit you launched remotely. A browser started outside the graphical session inherits XDG_SESSION_TYPE=tty, and while pcscd may still answer, the certificate prompt has nowhere to appear — so it silently sends nothing.

3 · Trust this bench

This site's certificate is issued by our own authority. Download the root certificate — Chrome users already imported it with the certutil line above; in Firefox use Settings → Privacy & Security → Certificates → View Certificates → Authorities and tick “trust to identify websites”. The same root signs the object store, so importing it once quiets both.

Then reload this page. The browser will ask which certificate to send — pick the one whose usage includes client authentication; a card normally also carries a separate signing certificate, which will not work here.