Décoder le passe sanitaire

Vous voilà vacciné contre la (le ?) Covid-19 avec 1, 2, voire 3 doses espacées. Pour l'occasion, on vous remet un certificat de vaccination avec un immense QR code à enregistrer dans l'application TousAntiCovid.

Un QR code (et tout système de code barre apparenté) est un moyen de stocker de l’information. Les versions récentes du pass sanitaire sont alignées depuis le 1er juillet 2021 sur son équivalent européen : le Digital Green Certificate (DGC), devenu European Digital Covid Certificate (EUDCC), qui se base justement sur un QR code. Que contient-il ?

Nous allons d'abord voir comment récupérer le contenu du QR code. Puis, nous verrons rapidement ce contenu. Ensuite, nous parlerons de la sécurité mise en place autour du certificat et nous finirons en comparant avec le système existant.

Récupérer le contenu

Pour pouvoir lire le contenu, vous pouvez au choix utiliser une bibliothèque comme ZXing ou allez directement faire une recherche sur "online qr code scanner", pour trouver un scanner qui fonctionne avec votre navigateur et votre webcam (par exemple, https://webqr.com/).

Ce QR code contient un certificat compatible, mais non valide. Vous ne pourrez pas le lire avec l'application TousAntiCovid. En dehors du problème de signature, il indique que Jean Martin (né le 3 février 1970) s'est fait vacciner le 1er juillet 2021 avec le vaccin de Pfizer.

Vous récupérez une chaîne de caractères commençant par HC (pour Health Certificate), un numéro de version (1, 2...), : et succession de caractères.

Le QR code ci-dessus donne la chaîne suivante (les sauts de ligne ont été ajoutés pour des questions de présentation) :

HC1:6BF$RDA-SMAHN-H6SKJPT.-7G2TZ97+S8Y4CXEJW.TFJTXG4DCESYCTSJ2TP$2G*P5Y
IJ6S4HZ6SH9+2QH/56SP.E5BQ95ZM376ZIE7PM1VE.Q6T:H:1NPK9/1AAJ1KK9%OC+G9QJP
NF67J6QW6D9RY466PPXY0E7J7UJQWT.+S1QDC8CI6C6XIO$9KZ56DE/.QC$Q3J62:6LZ6O5
9++9-G9+E93ZM$96PZ6+Q6X46+E54A9NF625F646L+9AKPCPP7ZMN27QW6ZOQ.NE/E2$4JY
/K9:K4F7D*G2SV /KF-KXIN2SV6AL3*I**GYZQVG9YJC/HLIJLKNF8JF1727WLTPL 6KNYM
B26REDFAQOQUX9RGQR.RE1G6*%3PNNPXSAXB*LM.NEMUN50I++VKZ39GTLV75+UJ+0W8J:A
T0F6 WAKWVV7U*V7J:VM30AGRK2

Le contenu de cette chaîne de caractères se base sur des technologies standardisées (ou presque...). En effet, en retirant l'en-tête (HC1:), la chaîne que vous obtenez est une chaîne encodée en Base 45. Base 45 est lié à une future RFC (encore en brouillon actuellement) qui se base sur un ensemble de 45 caractères pour encoder des données binaires. Il faut 3 caractères pour encoder 2 octets.

Il est possible de trouver une bibliothèque Java pour gérer l'encodage Base 45.

"io.github.ehn-digital-green-development" % "base45" % "0.0.3"

Cette bibliothèque est directement développée par l'organisation Github, responsable de la mise en place du système EUDCC : European eHealth Network - Digital Covid Certificate Coordination.

Elle s'utilise ainsi :

val base45Content: String   = qrCodeData.split(":", 2)(1).trim
val binaryData: Array[Byte] = Base45.getDecoder.decode(base45Content)

Les données obtenues sont des données compressées avec ZLIB. Le JDK inclut cette lib.

val inflater = new Inflater()
inflater.setInput(binaryData)
val buffer: Array[Byte] = Array.ofDim[Byte](2048)
val length: Int         = inflater.inflate(buffer)
inflater.end()

val data: Array[Byte] = Array.copyOf(buffer, length)

À ce niveau, nous obtenons une structure de type CBOR. CBOR est un format de donnée binaire qui est un sur-ensemble de JSON sur le plan sémantique et qui permet d'avoir un encodage compact. CBOR est spécifié par la RFC 8949.

La structure CBOR que nous récupérons du QR code répond aux spécifications COSE (RFC 8152 - draft). Cette structure présente 3 champs :

  • protected : contenant un document CBOR au format binaire et représentant des paramètres.
  • unprotected : contenant une table représentant des paramètres complémentaires.
  • Le contenu du message au format binaire

Un dernier champ peut être ajouté afin d'y déposer une signature calculée en fonction des champs précédents.

Il existe différentes bibliothèques gérant le format CBOR, dont une extension de Jackson. Cependant, cette extension ne permet d'avoir qu'une perception limitée à la perception JSON, sans pouvoir explorer la variété de type que propose CBOR. La plupart des projets autour du certificat européen utilisent la bibliothèque CBOR-Java.

Je vous propose d'utiliser ici la bibliothèque ci-dessous, ce qui permettra en plus de vérifier le respect du standard au niveau du certificat européen.

"co.nstant.in" % "cbor" % "0.9"

La récupération du modèle mémoire de la structure s'obtient de la manière suivante :

val healthCertificate: List[DataItems] = CborDecoder.decode(data)

Pour rappel, les étapes pour récupérer de l'information intelligible sont :

  1. Analyse et retrait du préfixe HCn:
  2. Décodage base 45
  3. Décompression ZLIB
  4. Analyse avec un parser CBOR

Dans ces phases, nous n'avons pas eu affaire à du chiffrement. Il n'y a pas de mot de passe ou d'autres systèmes permettant de protéger le contenu. Au contraire, ce contenu est directement accessible à partir de bibliothèques librement accessibles.

Contenu

Il y a trois champs qui vont nous intéresser :

  • protected qui contient des informations sur l'algorithme utiliser pour la signature et un keyId qui permet de retrouver la clé publique pour vérifier la signature. Nous en parlerons plus loin.
  • Le contenu qui conserve les informations du certificat.
  • La signature qui garantit la validité du certificat. Nous en parlerons aussi plus loin.

Le champ unprotected n'est apparemment pas utilisé actuellement.

La partie contenu est équivalente à un document JSON avec 3 niveaux d'imbrication. Le premier niveau donne l'identifiant de l'émetteur du certificat et sa période de validité. De notre exemple précédent, on obtient :

Issuer (field 1):     CNAM
Issued at (field 4):  2021-07-01
Expired at (field 6): 2023-07-01

Un 4e champ accompagne cette structure. Ce champ est annoté -260 et il contient les faits à l'origine du certificat.

Parmi ces informations, il y a tout d'abord la version du schéma de certificat utilisé (clé ver). Nous y trouvons une structure contenant votre nom (clé nam), ainsi que votre nom encodé à la manière de ce que vous pouvez trouver en bas des cartes d'identité ou des passeports. Vous trouvez aussi votre date de naissance (clé dob).

Un dernier champ contient la liste des vaccins (clé v). Avec une capacité maximale théorique de 2953 octets, il est, en effet, possible de stocker plusieurs actes dans un QR code, qu'il s'agisse de tests, de vaccins ou d'infection. À titre indicatif, la structure complète de l'exemple vu ci-dessus fait 300 octets. De ce fait, le QR code EUDCC peut faire office de carnet de vaccination.

Au niveau de chaque acte de "vaccination", nous avons tout d'abord un identifiant unique appelé UVCI (clé ci), qui apparait dans notre structure sous forme d'URN. Nous décrirons cet identifiant plus loin. Nous avons ensuite le pays émetteur (clé co). Pour les vaccins, nous trouvons derrière, le nombre de doses reçues (clé sd), le nombre de doses nécessaires (clé dn), la date de la dernière dose (clé dt), le code du fabricant du vaccin (clé ma) et le code produit administré (clé mp). Pour ces codes, l'ensemble des valeurs sont décrites dans un document accessible. Dans cette structure, nous allons aussi trouver l'agent ciblé (clé tg — c'est la Covid-19), le type d'administration.

Avec notre exemple, nous avons les données suivantes :

ci: urn:uvci:01:FR:AB123Z#8
co: FR
dn: 2
dt: 2021-07-01
is: CNAM
ma: ORG-100030215 (Biontech Manufacturing GmbH)
mp: EU/1/20/1528 (Comirnaty)
sd: 2
tg: 840539006 (COVID-19)
vp: J07BX03 (covid-19 vaccines)

Les données que nous voyons sont certes un exemple avec un faux certificat, mais elles sont proches de ce que vous avez comme certificats (si vous êtes vaccinés) ou de ce que vous aurez (si vous comptez vous faire vacciner). Ces données sont avant tout factuelles et traduisent en partie le manque de connaissance scientifique sur la Covid-19 de par l'absence de date de fin de validité du vaccin. Nous avons seulement une absence de validité du certificat, ce qui est différent.

Unicité de l'information

Nous voyons qu’en utilisant quelques bibliothèques sur le Net, nous pouvons accéder à des informations personnelles du certificat, sachant que ces informations ne sont pas chiffrées. Néanmoins, elles ne sont pas nécessairement suffisantes pour vous identifier : combien de Jean Martin sont nés le même jour dans tous les pays participants au programme DGC ? D’un autre côté, il n’y a probablement pas beaucoup de Côme Batz de Saint-Anmien. Il est nécessaire d'accompagner le certificat d'un document de type CNI ou passeport, par exemple, pour être sûr qu'il n'y a pas usurpation d'identité. Il reste à ce niveau à comprendre ce que vaut l’UVCI vu précédemment.

L'UVCI est un identifiant unique qui correspond à un Unique Vaccination Certificate/Assertion Identifier. L'UVCI n'est pas nécessairement un URN, mais il doit contenir un numéro de version et un code pays émetteur en préfixe, ainsi qu'un checksum en suffixe. Le reste de l'UVCI ainsi que le format peut varier d'un pays à l'autre.

C'est l'UVCI qui assure l'unicité de l'acte de vaccination (ou du test ou de l'infection). Il n'est pas exploitable directement à partir d'un scanner sans connexion. En effet, il ne doit pas contenir de données personnelles. Par contre, il peut agir comme une clé étrangère et permet de retrouver des informations complémentaires sur une autre base de données. On s'attend à ce que cette base soit gérée par un organisme de Sécurité sociale et ne soit pas si facilement accessible (!?).

Sécurité

À ce niveau, nous n’avons pas encore vérifié si le pass est valide. Nous avons accès à certaines informations personnelles, mais nous n’avons pas montré si ces informations sont certifiées (y a-t-il un cachet, un tampon, une signature d’une autorité reconnue ?) et nous ne savons pas si les informations sanitaires sont valides.

Pour cela, il faut s’intéresser au reste de la structure COSE. Dans la partie protected, qui contient le binaire d'une structure CBOR, nous allons trouver deux champs :

  • 1 représentant l'algorithme de chiffrement (ici -7).
  • 4 représentant le kid ou KeyID.

Le kid est un identifiant en base 64 faisant référence à une entrée dans une base de données des organismes délivrant le certificat numérique (organisme administratif de Sécurité sociale, hôpital, centre de test...). Cette base de données contient des informations au format LDAP concernant l'organisme. Elle contient la clé publique de ces organismes. Chaque pays a une copie de cette base de données (une copie est disponible dans le projet sanipasse).

La partie signature de la structure récupérée se base sur algorithme de chiffrement utilisant un système de clé privée / clé publique. La signature est générée à partir du contenu de la structure COSE, de la clé privée de l'organisme faisant autorité et d'un sel "Signature1" (appelé context string). L'algorithme utilisé est ECDSA avec la fonction de hachage SHA-256. La vérification se fait en utilisant la clé publique, le contenu COSE, le sel et la signature. L'algorithme indique si l'ensemble est cohérent. Si la moindre information est changée dans la structure COSE ou dans la signature, la vérification échouera.

Cette approche permet de ne pas communiquer d'information lors d'une vérification. Seule la clé de l'organisme (le kid) est transmis pour récupérer la clé publique. D'ailleurs, il est possible de conserver la base des organismes au sein du système de vérification.

Fiabilité de la signature

Tant que l'algorithme utilisé est considéré comme suffisamment sûr pour signer des documents et vérifier ces signatures, il n'y a pas de faille. Par contre, c'est l'employé qui crée la liaison entre l'acte médical et le certificat. Il a ainsi la possibilité de délivrer certificat sans acte médical s'il le souhaite. Le certificat est alors techniquement valide et passera tous les contrôles, mais il est faux vis-à-vis de la loi. C'est ce qui est arrivé durant le mois de juillet.

Pour rappel, posséder un faux certificat (tout comme n'importe quel faux documents) est punie par de l'emprisonnement et une amende (Code Pénal, article 441-1 à 441-12), pouvant impliquer des peines complémentaires. La peine est plus lourde dans le cas de son utilisation. Il en va de même pour la personne qui crée un faux certificat.

Systèmes existants

On peut s’intéresser à faire un rapprochement entre l’EUDCC d’un côté et le numéro de Sécurité sociale et le carnet de santé de l’autre.

Le numéro de Sécurité sociale est une invention de René Carmille (par la suite résistant français, mort à Dachau) adoptée par la Sécurité sociale en 1946. Certaines utilisations controversées de ce numéro ont conduit à la création de la loi Informatique et Liberté en 1978, ainsi qu’à la création de la CNIL. Le numéro de Sécurité sociale est un numéro qui permet d’identifier indirectement une personne. Il ne contient ni nom et prénom, ni dossier médical, mais il permet de connaître le sexe d’une personne, sa date de naissance, sa commune de naissance. Il est unique à chaque personne enregistrée au sein de la Sécurité sociale.

Le carnet de santé est créé en 1938 par l’artiste Louise Hervieu. Il est adopté un an plus tard par le gouvernement et est rendu obligatoire en 1945. Son contenu a évolué au cours du temps. Mais il est avant tout personnel et soumis au secret professionnel. Ce carnet contient l’identification de la personne, son numéro de Sécurité sociale, un suivi détaillé de la santé de la personne durant son enfance, ainsi que l’ensemble des vaccins réalisés.

Si votre organisme de Sécurité sociale ne connait pas le contenu de votre carnet de santé, elle voit régulièrement passer vos actes médicaux, afin de vous fournir les remboursements qui vous sont dus. Ainsi que votre mutuelle, si vous en avez une. Ces actes médicaux ne sont pour la plupart pas inscrit dans votre carnet de santé. Ces organismes possèdent même de plus de détails en cas d'arrêt de travail.

Mais en dehors de votre organisme de Sécurité sociale, aucun autre organisme ne possède d'information santé… À part, votre mutuelle, votre smartphone et ce qu'il peut y avoir derrière.

Conclusion

Le passe sanitaire est devenu depuis le 1er juillet 2021 un certificat européen de vaccination ou non-infection, qui pour le moment s'applique à la Covid-19. Il apparaît sous forme de QR code qui se décode en se basant sur des technologies standardisées ou clairement documentées.

Cependant, le certificat contient certaines données personnelles qui sont portées à la connaissance des personnes physiques ou morales en charge de la vérification. Elles ne suffisent pas pour vous identifier complètement, mais elles ont néanmoins un fort potentiel.

Au niveau sécurité, la falsification d'un certificat est très difficile sans avoir la clé privée utilisée par signer le document. Les récents événements ont montré que le manque de loyauté du personnel ayant accès à la clé privée est un risque à prendre en compte dans ce système, même si ce sujet est pris en compte par le législateur.

Il reste que le certificat Covid européen nous met face à un niveau d'échange de données personnelles, en particulier de données de santé, que nous n'avons pas encore connu dans notre société moderne. Les circonstances étant exceptionnelles, il serait alors normal d'accepter ce dispositif.

Il y a un message caché dans le QR code du certificat ci-dessous…

Lien

European eHealth network - Digital Covid Certificate Coordination est une organisation Github qui regroupe l'ensemble des projets autour du certificat Covid européen, afin de proposer aux États membres une plateforme commune sur ce sujet : https://github.com/ehn-dcc-development

Le lien précédent est à compléter avec cette organisation Github autour de l'EUDCC : https://github.com/eu-digital-green-certificates

Le projet sanipasse de Ophir LOJKINE propose un service hébergeable permettant de vérifier des passes sanitaires et autres certificats Covid européens.

Le thread Twitter de @gilbsgilbs ci-dessous permet de compléter les explications de l'article.