qredential

SD-JWT · Token Status List · base45

La réponse est déjà dans le code

Un justificatif qui se prouve lui-même. Signature, expiration, révocation et claims, tout est contrôlé sans qu'une seule requête ne quitte l'appareil.

TypeScript, zéro dépendance à l'exécution, WebCrypto uniquement. Node, navigateurs et React Native, parce que l'appareil qui vérifie est le plus souvent un téléphone.

signature d'un justificatif de démonstration…
 
 
requêtes réseau· vérifié en·

Ce que cela fait, concrètement

Une attestation est une affirmation que quelqu'un a signée. « Cette personne a plus de 18 ans. » « Cette personne peut conduire. » C'est la signature qui lui donne sa valeur : elle dit qu'une autorité répond de cette phrase et que personne ne l'a modifiée ensuite.

Sur papier, et dans un PDF, une seule signature couvre tout le document. Pour en prouver une ligne, il faut tout remettre. Montrez votre permis de conduire uniquement pour prouver votre âge et votre interlocuteur apprend aussi votre adresse, votre numéro de permis et votre date de naissance exacte. Il n'a jamais demandé cela. Il l'a maintenant.

La divulgation sélective supprime ce marché. L'émetteur signe chaque donnée séparément, et l'attestation ne transporte qu'une empreinte de chacune. Vous choisissez ce que vous révélez, et le reste demeure une empreinte qui ne dit rien de son contenu. La signature reste valable, car elle n'a jamais porté sur un bloc indivisible.

Tout cela tient dans le code que le vérificateur lit : la signature, les empreintes et les données que vous avez choisi de montrer. Rien n'est téléchargé pendant la vérification, donc une porte, un autobus, un dispensaire rural ou un avion en vol peuvent vérifier une attestation sans aucun réseau.

Il reste une pièce, et c'est précisément celle qu'on oublie. Tout ce qui peut être scanné peut être photographié. Celui qui présente doit donc aussi signer un défi nouveau avec une clé privée qui ne quitte jamais son appareil. Sans cette étape, la capture d'écran de l'attestation d'une autre personne passerait. Cette bibliothèque refuse toute présentation qui en est dépourvue.

Faite pour le moment où il n'y a pas de réseau

J'ai construit l'eCNH, le permis de conduire numérique brésilien, utilisé par plus de 40 millions de personnes. Ce qui m'a le plus appris n'était pas l'application. C'était le bord de la route : un agent scannant un permis sur une nationale avec une barre de réseau, ou aucune, et qui a besoin d'un oui ou d'un non en moins d'une seconde.

Tout ce qu'il faut pour cette réponse tient dans le code. La signature prouve l'émetteur, les claims sont là, et la seule chose qui vienne de l'extérieur est la clé publique de l'émetteur, qui change si rarement qu'on peut la livrer avec l'application et la rafraîchir une fois par semaine.

Des bibliothèques existent pour cela. Ce sont des SDK d'entreprise : lourds, liés au profil d'un seul pays, et écrits comme si vous travailliez déjà dans l'identité numérique. Voici la version qu'un ingénieur produit ajoute un mardi.

Trois parties, et aucune n'est un serveur

01 · ÉMETTRE

Signer chaque claim une fois

L'émetteur décide quels claims pourront être retenus plus tard, et signe une empreinte pour chacun d'eux.

02 · PRÉSENTER

N'envoyer que ce qui est demandé

Le portefeuille laisse de côté les claims qu'il garde. La signature de l'émetteur reste valable sur ce qui reste.

03 · VÉRIFIER

Répondre sans demander à personne

Signature, expiration, révocation et chaque divulgation, contrôlées face à une clé embarquée sur l'appareil.

Prouvez que vous avez plus de 18 ans sans livrer votre date de naissance

Les lois sur le contrôle d'âge arrivent plus vite que les outils. L'implémentation habituelle fait téléverser au client une photo de sa pièce d'identité chez un tiers, ce qui est un désastre pour la vie privée et une fuite en attente.

La divulgation sélective fait cela correctement. Le vérificateur ne peut pas apprendre la date de naissance même s'il le veut, parce que cette valeur n'a jamais quitté le portefeuille. La propriété est cryptographique, pas une promesse dans une politique de confidentialité.

// Le justificatif contient nom, adresse, date de naissance et numéro de document.
// Le bar reçoit un booléen.
const presentation = await present(credential, { disclose: ['over_18'] })

const result = await verify(presentation, { trust })
result.claims             // { over_18: true }
result.claims.birth_date  // undefined, et n'a jamais été transmis
result.withheld           // 4, et il ne peut pas dire lesquels

Des chiffres réels, y compris celui qui dérange

Un permis de conduire réaliste, huit claims, validité de cinq ans, pointeur vers une liste de statut. Mesuré, pas estimé :

JustificatifCaractèresVersion du QR
tout visible~74018, se scanne bien
les huit claims divulgables~159027, trop dense
presenting only over_18~111522, encore dense
La divulgation sélective double presque le justificatif. Chaque claim divulgable coûte un sel plus une empreinte signée, et les empreintes restent dans la charge utile que le porteur révèle le claim ou non. C'est délibéré : un nombre d'empreintes qui diminuerait avec ce que vous révélez trahirait ce que vous avez retenu. L'économie au moment de la présentation est donc de trente pour cent ici, pas des quatre-vingts que l'intuition promet. Rendez deux ou trois claims divulgables, pas tous, et laissez fits() vous dire où vous en êtes avant d'imprimer quoi que ce soit.

Ne me croyez pas sur parole

Le playground exécute toute la bibliothèque dans votre navigateur et lui envoie huit attaques réelles. Chacune affiche le code de refus qu'elle attend, de sorte que vous pouvez contrôler la bibliothèque face à ses propres affirmations plutôt que de faire confiance à un README.

Modifier un claim dans la charge utile
bad_signature
Inventer un claim jamais émis
digest_mismatch
Envoyer une divulgation deux fois
digest_mismatch
Signer avec la mauvaise clé
bad_signature
Se faire passer pour une autre autorité
unknown_issuer
L'utiliser dans dix ans
expired
L'utiliser après révocation
revoked
Se cacher derrière une liste périmée
status_list_stale
Rejouer une présentation enregistrée
holder_proof_invalid
Présenter la photo du code d'un autre
holder_proof_missing

Pourquoi celle-ci, et quand s'abstenir

Cinq raisons de la choisir, puis la partie honnête.

  • Environ 1 300 lignes qu'on peut lireAssez petite pour qu'une seule personne la lise entièrement en un après-midi et sache ce qu'elle fait. Une sécurité qu'on ne peut pas lire est une sécurité acceptée sur parole.
  • Aucune dépendanceRien venu de npm à l'exécution. Il n'y a pas d'autre chaîne d'approvisionnement à auditer que celle-ci, et rien qui puisse changer sous vos pieds la semaine prochaine.
  • Elle refuse ce qu'elle ne peut pas vérifier entièrementPas de validation partielle, pas d'avertissement qu'on peut ignorer. Chaque échec revient sous la forme d'un motif nommé, que vous pouvez journaliser et traiter, jamais d'un simple faux.
  • Elle tourne là où la vérification a lieuNode, Deno, Bun, navigateurs, React Native et edge workers. Le même code partout, sur la cryptographie standard déjà intégrée à la plateforme.
  • Testée de trois façonsDes tests unitaires, les vecteurs officiels publiés avec la RFC 9901, et des tests de propriétés qui lui lancent des entrées aléatoires et malformées en cherchant le cas qui passerait au travers.

Et quand ce n'est pas le bon outil.

  • Il vous faut des permis de conduire ISO 18013-5C'est un autre encodage, CBOR et COSE, et une autre norme. Cette bibliothèque parle SD-JWT, le format qu'utilisent les portefeuilles européens et les spécifications OpenID. Problème voisin, travail différent.
  • Vous voulez un portefeuille completCeci vérifie et présente. Cela ne stocke pas les attestations, ne gère ni les appareils ni l'inscription. C'est une pièce, faite pour vivre à l'intérieur de votre produit.
  • Il vous faut un audit externe avant un déploiement réglementéIl n'en existe pas encore. Les tests et les vecteurs de la RFC sont publics, chaque ligne aussi, mais pour un déploiement réglementé prévoyez un budget pour votre propre revue.

Installer

npm i qredential

Node 20 ou plus récent, tous les navigateurs actuels, React Native. Environ 1 300 lignes de code sans aucune dépendance à l'exécution, précisément pour que le lire avant de lui faire confiance soit réaliste.

Des normes, pas des inventions

  • SD-JWT, RFC 9901divulgation sélective et liaison de clé, imbriquée et récursive, le mécanisme qu'utilise le portefeuille d'identité européen
  • SD-JWT VCla forme du justificatif
  • Token Status Listune révocation qui fonctionne depuis une copie en cache
  • base45, RFC 9285l'enveloppe du QR, choisie pour la compatibilité des lecteurs

Pas de mDL ISO 18013-5, qui est du CBOR et du COSE plutôt que du JWT. C'est à la feuille de route, et un justificatif qui utilise quelque chose de non pris en charge est refusé plutôt que compris à moitié. Revendiquer la moitié d'une norme de conformité est pire que ne rien revendiquer.