FreeHSM C

An open-source PKCS#11 v3.2 cryptographic module under Simorgh Labs

View the Project on GitHub afchine1337/freehsm

fhsm-gui — a desktop interface over the PKI tools

A GTK 4 window that does what fhsm-token, fhsm-csr, fhsm-ca and fhsm-sign do, through the same operations (tools/pkiops), and shows every PKCS#11 call it makes as it makes it.

It adds no second way of talking to the module. The command-line tools and the window call the same functions; tests/pki_tools_characterize.sh checked, byte for byte, that moving the tools onto those functions changed nothing they print. The design and its stages are in fhsm-gui-plan.md.


Building and running

sudo apt install libgtk-4-dev            # once
make PROFILE=all-mechanisms              # for the composite; the other algorithms need no profile
make PROFILE=all-mechanisms gui
FHSM_TOKENS_DIR=~/fhsm-tokens ./tools/fhsm-gui

make gui is not part of make all: the module and the command-line tools do not depend on GTK, and a server needs neither.

The module is loaded from the path in the window (./libfreehsm.so by default) and can be unloaded and another loaded without restarting. The environment is the module’s, as for any other application: FHSM_TOKENS_DIR says where the tokens are, and a build of your own is unsigned until make integrity signs it. If loading fails with 0x80000002, the module’s integrity self-test refused to start; the terminal that launched the window says which of its three reasons applies.


Two modes

A switch at the top chooses between them. Both keep the Token and Signing tabs.

Exploration (the default) offers every operation with the command line’s defaults, in two more tabs, Certificates and Revocation. It is for learning the module and the PKI, and for the exception operator mode refuses.

Operator mode replaces those two tabs with three guided ones, CA, Issue and Revoke, that work for one CA set once, and refuses what the command line leaves to its user (see below).


The tabs, and the commands they correspond to

Tab What it does Command line
Token slots, initialise a token, log in and out, keys and certificates on the token and their attributes, generate a key pair or a secret key, delete fhsm-token init, fhsm-csr keygen --alg, fhsm-crypt keygen, list, show, delete
Certificates request, self-signed root, issue from a request fhsm-csr csr, fhsm-csr root, fhsm-ca issue
Revocation the revocation database, revoke, publish a CRL, answer an OCSP request fhsm-ca revoke, crl, ocsp-respond
Signing raw detached signatures and CMS, signed and checked fhsm-sign sign, verify, cms, cms-verify
Encryption encrypt a file for a key on the token or for a certificate; decrypt one fhsm-crypt encrypt, decrypt
CA, Issue, Revoke operator mode: the same operations, for one CA (the same)

The algorithm is chosen where a key pair is generated — the Token tab, and Create a new CA in operator mode — from the list fhsm-csr keygen --alg takes: the composite, ECDSA P-256 and P-384, RSA-PSS and PKCS#1 v1.5, Ed25519, ML-DSA-44/65/87. Nothing else asks: every other operation signs with the algorithm of the key it is given, and the key list shows each key’s. The composite exists only in all-mechanisms builds; the others work with the default profile. CMS uses the key’s own digest when it signs, and the one the structure names when it checks.

The defaults are the tools’: a root for 3650 days and serial 1, a certificate for 365 days or 30 for a delegated OCSP responder, a CRL for 30 days, an OCSP response for 7. Certificates and requests are read as DER or PEM; output is written as either where the tools offer both. An issued certificate’s serial is shown with the result — it is 160 random bits, and the number a revocation will ask for — and From certificate… reads it off the file instead of having it copied by hand.

Secret keys are generated from the same list as key pairs: after the signature algorithms come aes128 and aes256, which encrypt and wrap, and hmac, a 32-byte secret for MACs — all sensitive and never extractable. Selecting a row shows the object’s attributes below the list: class, label and CKA_ID, usage, size or curve, allowed mechanisms, whether it is sensitive or extractable and was generated on the token; for a certificate, its subject, issuer, serial and validity. A key’s value is never read.

Deleting starts from a row of the Token tab’s list. Delete… shows every object sharing that row’s label — a private key, its public half, a certificate — each with a tick box, and ticks only the one selected: what goes is the operator’s to say. Nothing deleted from a token comes back. Operator mode refuses to delete the CA’s key; fhsm-crypt delete does the same work from the command line, and destroys nothing without --yes.

Encrypting for an AES key or an rsa-oaep pair on the token needs a login; encrypting for the holder of a certificate does not — it uses only their public key. Decrypting finds the key from the file and says which one opened it. The format is CMS AuthEnvelopedData with AES-256-GCM, which openssl cms reads; an existing file is never written over, and a file that does not authenticate leaves nothing behind (FHSM_CRYPT.md).

Recording a revocation needs no login, as with fhsm-ca revoke. Checking a CMS needs neither the token nor a login: the signer’s certificate is inside it.


Operator mode

The CA tab sets, once: the CA’s key, its certificate, its revocation database, the file where its CRL is published, and the URLs at which that file is served. Create a new CA generates the key pair and the self-signed root and makes them the CA.

Refused, with no “continue anyway” — whoever needs the exception has exploration mode and the command-line tools, which are unchanged:

Revoke and publish records the revocation and publishes a new CRL at once: in operator mode a revocation is not finished until a list says so.

The published CRL’s nextUpdate is read from the file itself and re-read every minute. Once less than a third of its validity is left, the CA and Issue tabs say so; once it has passed, they say that, and issuing is refused until a new list is published. Nothing about this is stored in the revocation database, whose format fhsm-ca and fhsm-service share.

The CA set on the CA tab is not remembered between runs.


The PIN

Typed into a password field, copied into a buffer the program owns, the field cleared at once, and the buffer wiped (OPENSSL_cleanse) as soon as C_Login has answered. The PIN is never an argument, never in the environment, never written anywhere, and never in the call log.

That is weaker than the module’s own handling, and said here rather than discovered: GTK may copy what is typed internally, and the password field’s buffer is locked against swapping only if RLIMIT_MEMLOCK has room left. Once a FreeHSM module is loaded it usually has none — its secure heap is sized to the whole default limit — and GTK prints couldn't lock 16384 bytes of memory and carries on with ordinary memory.


The call log

The right-hand pane lists every PKCS#11 call: the function, a summary of its arguments, the return value by name, and how long it took. It shows handles, slots, mechanisms, attribute types and byte counts — never a PIN, its length, or any attribute value. tests/test_pkiops.c logs in with distinctive PINs and fails if either appears in any record.


Where the window differs from the command line


What it does not do