Bring your public keys
Put the public half of your SSH, PGP, minisign, Ed25519 or ML-DSA keys on your card with a proof anyone can check, then hand them to git, ssh-keygen or gpg.
Add the public half of the keys you already use: SSH, PGP, minisign or ML-DSA. The private key never leaves your machine. You prove the key is yours by signing one challenge with it.
Veil never asks for a private key. Paste only the public key and the signature of the challenge. If you paste a private key here by mistake, treat it as exposed and replace it.
On your card, choose Add a public key under Devices and keys, and paste the public key. The page reads its type, then gives you a short challenge as a file, veil-challenge.txt. It names your card, the key, your browser’s device key and the latest cosigned checkpoint of the log, so the signature can’t be dated earlier or reused on another card.
Only the primary key and the signing subkeys of an OpenPGP key reach your card. The page lists the user IDs the key carries and keeps one only if you tick it. These names and addresses become part of the public record of your card, in the log, and stay in its history. Photos and other people’s certifications never go on the card.
Sign the challenge on your machine#
SSH keys (Ed25519, ECDSA P-256 and P-384, RSA from 2048 bits) sign with namespace veil. A signature made for git doesn’t count here.
ssh-keygen -Y sign -n veil -f ~/.ssh/id_ed25519 veil-challenge.txt
cat veil-challenge.txt.sigAn OpenPGP key (version 4: RSA from 2048 bits, ECDSA P-256 or P-384, Ed25519) signs the file as it is, with the primary key or a signing subkey. Paste the .asc file; a clear-signed file works too. A signature made with SHA-1 doesn’t count.
gpg --local-user <fingerprint> --armor --detach-sign veil-challenge.txt
cat veil-challenge.txt.ascminisign signs the file as it is, in either of its two forms. Paste the .minisig file.
minisign -Sm veil-challenge.txt
cat veil-challenge.txt.minisigA raw Ed25519 or ML-DSA key (44, 65 or 87) signs the bytes of the challenge. With OpenSSL 3.5:
openssl pkeyutl -sign -inkey key.pem -rawin -in veil-challenge.txt | base64On Windows, sign the file the page downloads. A copy pasted into Notepad works too, with CRLF line endings or a BOM, and your proof records which form you signed. A file saved by Windows PowerShell with > is UTF-16: the page tells you, and you save it as UTF-8 instead.
Paste the signature and choose Check and add the key. Your browser checks it before signing the new version of your card, and the server checks it again.
Use the public keys in your tools#
GET /u/{card}/keys.txt gives the public keys of a card as a file. allowed_signers works with git and ssh-keygen -Y verify, authorized_keys with a server, minisign with minisign -V -p, and pgp is an armoured keyring for gpg --import. gpg imports a key only if it carries at least one user ID. Add fp=<fingerprint> for one key alone; GET /u/{card}.keys is the authorized_keys file at the address people know from GitHub. The file is the server’s word: check each proof on the card before relying on it.
curl -fsS 'https://veil.rip/u/1/keys.txt?format=allowed_signers' > allowed_signers
git config gpg.ssh.allowedSignersFile "$PWD/allowed_signers"
git log --show-signature -1curl -fsS 'https://veil.rip/u/1/keys.txt?format=pgp' | gpg --importFind the person behind a key#
GET /v1/lookup?fingerprint=SHA256:… finds the card that holds an SSH or ML-DSA key. A minisign key ID works too, and so do the 40 hex digits of an OpenPGP fingerprint, with or without spaces. ?key= takes the OpenSSH line or the armoured OpenPGP public key as you would paste it. A key sits on one card at a time.
Check a proof yourself#
Read state.external from the card JSON. For each key, rebuild the challenge from the card number and the entry’s fields, in the form proof.variant names (absent: the bytes as offered; crlf, bom, noeol and their combinations, as docs/formato-v2.md, section 4, spells them), check the quoted checkpoint against the log’s witness policy, check that the device key in proof.by was active in the version that added the key, and verify the signature. assets/veil-external.js does all of this and can be used on its own. For OpenPGP, pub is the base64 of the key’s packets: the primary key with its self-signatures, the user IDs the person chose, the signing subkeys.