L’objectif est de voir pas à pas comment sont stockées et quelles données sont présentes dans un QR-CODE dédié au passe sanitaire.
Pour cela nous utiliserons une plateforme Linux et lancerons quelques commandes Shell afin de voir toutes les étapes et structures qui sont incluses dans le QR-Code.
Toutes les références seront indiquées au fur et à mesure quelles soit techniques (norme RFC, IETF, etc.) ou descriptives (documents européens dans la plupart des cas).
I Ressources initiales
I.1 Quelques liens
Liens pour comprendre :
- documentation européenne : https://ec.europa.eu/health/ehealth/covid-19_fr
- explication générale :
- https://blog.callicode.fr/post/2021/covid_pass.html (en français) ;
- https://gir.st/blog/greenpass.html ;
- https://harrisonsand.com/posts/covid-certificates/ ;
- https://www.bortzmeyer.org/7049.html lire un objet binaire CBOR (en français) ;
- obtenir des QR-Code de test : https://github.com/eu-digital-green-certificates/dgc-testdata ;
- autres :
- les différents type de codes barre : https://fr.wikipedia.org/wiki/Liste_des_symbologies ;
- un lecteur de CBOR on line (texte vers Objet CBOR) : http://www.cbor.me/.
I.2 Outils :
Quelques outils qui seront utilisés (avec Linux Ubuntu LTS 20.04) :
sudo apt install zbar-tools #permet de scanner un qr-code et d'en sortir du texte
sudo apt install zlib1g #librairie zlib pour décompresser
sudo apt install qpdf # outil qui intègre zlib et utilisable en ligne de commande
sudo apt install qrencode # générer l'image d'un qr-code
Lien pour récupérer les sources d’un décodeur base45 : https://github.com/ehn-dcc-development/base45-ansi-C
# outils pour la compiltation
sudo apt-get install build-essential
# création du répertoire qui va recevoir le code source
mkdir base45
# récupération du code source
git clone https://github.com/ehn-dcc-development/base45-ansi-C.git --depth 1 --branch=main ./base45/
# compilation des sources
cd ./base45
sudo make
# copie de l'executable dans /bin pour qu'il soit accessible de tous...
sudo cp base45 /bin/base45
II Récupérer les informations binaires d’un QR-CODE
II.1 De l’image à la donnée binaire
Structure des données d’un QR-Code pour le pass sanitaire :
Les spécifications qui régissent comment sont stockées les données ou lurs structures se trouvent dans le document suivant : Technical Specifications for Digital Green Certificates Volume 3. Ce document parmi d’autres sont tous regroupés dans la page suivante : https://ec.europa.eu/health/ehealth/covid-19_fr.
Voici le QR-Code de test sur lequel nous allons travailler :

La première opération consiste à récupérer l’information brute contenue dans le QR-Code. En Shell elle s’obtient de la manière suivante :
zbarimg --raw --quiet qr_image.jpg | xxd # --raw : mode brut, cela permet d'enlever le type de code barre (ici un qr-code) afficher par défaut pour cette commande
ce qui donne :
00000000: 4843 313a 4e43 463a 3630 3341 3054 3957 HC1:NCF:603A0T9W
00000010: 5457 4753 4c4b 4320 344b 3639 3457 4a4e TWGSLKC 4K694WJN
00000020: 2e30 4a24 3643 2d37 5741 4230 584b 334a .0J$6C-7WAB0XK3J
00000030: 4353 4741 3246 3352 3850 5034 5632 4633 CSGA2F3R8PP4V2F3
00000040: 3556 5050 2e45 5935 302e 464b 385a 4b4f 5VPP.EY50.FK8ZKO
00000050: 2f45 5a4b 455a 3936 4c46 362f 4136 2e2e /EZKEZ96LF6/A6..
00000060: 4456 2544 5a4a 4330 2f44 3555 4120 5145 DV%DZJC0/D5UA QE
00000070: 4c50 4347 2f44 5955 4348 5938 3355 4147 LPCG/DYUCHY83UAG
00000080: 5643 2a4a 434e 4636 4634 3633 5735 4b46 VC*JCNF6F463W5KF
00000090: 3656 4636 4945 4353 4847 344b 4344 3344 6VF6IECSHG4KCD3D
000000a0: 5834 3742 3436 494c 3636 3436 482a 364d X47B46IL6646H*6M
000000b0: 5745 574a 4441 3641 3a39 3631 4136 5134 WEWJDA6A:961A6Q4
000000c0: 3745 4d36 4224 4446 4f43 3052 3633 4b43 7EM6B$DFOC0R63KC
000000d0: 5a50 434e 4636 4f46 3633 5735 2451 362b ZPCNF6OF63W5$Q6+
000000e0: 3936 2f53 4135 5236 4e46 3631 4737 3335 96/SA5R6NF61G735
000000f0: 3634 4b43 2a4b 4554 4636 4134 362e 3936 64KC*KETF6A46.96
00000100: 3634 3642 3536 3557 4543 2e44 3124 434b 646B565WEC.D1$CK
00000110: 5745 445a 4336 5643 5334 3436 2443 3457 WEDZC6VCS446$C4W
00000120: 4555 5043 334a 4355 4941 2b45 4424 2e45 EUPC3JCUIA+ED$.E
00000130: 4624 444d 5745 3824 4342 4a45 4d56 4342 F$DMWE8$CBJEMVCB
00000140: 3434 3524 4342 5745 522e 4347 5043 3457 445$CBWER.CGPC4W
00000150: 454f 5043 4538 4648 5a41 312b 394c 5a41 EOPCE8FHZA1+9LZA
00000160: 5a4d 3831 4737 3241 3632 2b38 4f47 374a ZM81G72A62+8OG7J
00000170: 3039 5534 3741 4238 5635 3954 2536 5a48 09U47AB8V59T%6ZH
00000180: 424f 3537 5834 3852 5549 5930 3358 514f BO57X48RUIY03XQO
00000190: 4b2a 465a 554e 4d20 5546 5934 4435 4320 K*FZUNM UFY4D5C
000001a0: 5333 5239 5557 2d32 522a 344b 5a4a 5435 S3R9UW-2R*4KZJT5
000001b0: 4d20 4d49 4d3a 3033 524d 5a4e 4120 4c4b M MIM:03RMZNA LK
000001c0: 544f 3334 5041 2e48 3531 3936 3650 5330 TO34PA.H51966PS0
000001d0: 4b41 502d 4b4c 5048 2e51 3624 4b53 544a KAP-KLPH.Q6$KSTJ
000001e0: 302d 4736 3538 524c 3548 5231 0a 0-G658RL5HR1.
A ce stade nous avons l’intégralité des données binaires de l’image QR-Code.
A titre d’informations, pour récupérer les données binaires dans une simple chaine de caractères :
zbarimg --raw --quiet qr_image.jpg | xxd -p -c 1000 # affiche les données binaires par bloc de 1000 octets
ce qui donne :
4843313a4e43463a3630334130543957545747534c4b4320344b363934574a4e2e304a2436432d3757414230584b334a43534741324633523850503456324633355650502e455935302e464b385a4b4f2f455a4b455a39364c46362f41362e2e445625445a4a43302f443555412051454c5043472f445955434859383355414756432a4a434e46364634363357354b4636564636494543534847344b43443344583437423436494c36363436482a364d5745574a444136413a3936314136513437454d36422444464f43305236334b435a50434e46364f46363357352451362b39362f53413552364e4636314737333536344b432a4b455446364134362e3936363436423536355745432e443124434b5745445a43365643533434362443345745555043334a435549412b4544242e454624444d5745382443424a454d5643423434352443425745522e434750433457454f5043453846485a41312b394c5a415a4d38314737324136322b384f47374a30395534374142385635395425365a48424f353758343852554959303358514f4b2a465a554e4d2055465934443543205333523955572d32522a344b5a4a54354d204d494d3a3033524d5a4e41204c4b544f333450412e4835313936365053304b41502d4b4c50482e5136244b53544a302d47363538524c354852310a
et inversement :
echo "4843313a4e43463a3630334130543957545747534c4b4320344b363934574a4e2e304a2436432d3757414230584b334a43534741324633523850503456324633355650502e455935302e464b385a4b4f2f455a4b455a39364c46362f41362e2e445625445a4a43302f443555412051454c5043472f445955434859383355414756432a4a434e46364634363357354b4636564636494543534847344b43443344583437423436494c36363436482a364d5745574a444136413a3936314136513437454d36422444464f43305236334b435a50434e46364f46363357352451362b39362f53413552364e4636314737333536344b432a4b455446364134362e3936363436423536355745432e443124434b5745445a43365643533434362443345745555043334a435549412b4544242e454624444d5745382443424a454d5643423434352443425745522e434750433457454f5043453846485a41312b394c5a415a4d38314737324136322b384f47374a30395534374142385635395425365a48424f353758343852554959303358514f4b2a465a554e4d2055465934443543205333523955572d32522a344b5a4a54354d204d494d3a3033524d5a4e41204c4b544f333450412e4835313936365053304b41502d4b4c50482e5136244b53544a302d47363538524c354852310a" | xxd -r -p
ce qui donne :
HC1:NCF:603A0T9WTWGSLKC 4K694WJN.0J$6C-7WAB0XK3JCSGA2F3R8PP4V2F35VPP.EY50.FK8ZKO/EZKEZ96LF6/A6..DV%DZJC0/D5UA QELPCG/DYUCHY83UAGVC*JCNF6F463W5KF6VF6IECSHG4KCD3DX47B46IL6646H*6MWEWJDA6A:961A6Q47EM6B$DFOC0R63KCZPCNF6OF63W5$Q6+96/SA5R6NF61G73564KC*KETF6A46.96646B565WEC.D1$CKWEDZC6VCS446$C4WEUPC3JCUIA+ED$.EF$DMWE8$CBJEMVCB445$CBWER.CGPC4WEOPCE8FHZA1+9LZAZM81G72A62+8OG7J09U47AB8V59T%6ZHBO57X48RUIY03XQOK*FZUNM UFY4D5C S3R9UW-2R*4KZJT5M MIM:03RMZNA LKTO34PA.H51966PS0KAP-KLPH.Q6$KSTJ0-G658RL5HR1
A ce stade nous avons donc récupéré les données brutes. Nous allons voir comment elles sont structurées.
II.2 Première structure de données
Après avoir retiré les informations binaires du QR-Code, nous obtenons la structure est la suivante:
[version][données]
La version est une donnée en clair. Elle permet d’identifier la version du pass sanitaire. A ce jour il existe 2 versions (page 6 du document européen)
- HC1 : Health Certificate 1
- HC2 : Health Certificate 2
Aujourd’hui c’est la version « HC1 » qui est utilisée pour la pass sanitaire (greenpass). Mais demain si une évolution sur la structure des données voit le jour c’est par cette valeur que nous le saurons.
DOnc pour obtenir les données utiles directement sans la version :
zbarimg --raw --quiet qr_image.jpg | cut -b5- # on enlève les 5 premiers bytes ...
ce qui donne :
00000000: 4e43 463a 3630 3341 3054 3957 5457 4753 NCF:603A0T9WTWGS
00000010: 4c4b 4320 344b 3639 3457 4a4e 2e30 4a24 LKC 4K694WJN.0J$
00000020: 3643 2d37 5741 4230 584b 334a 4353 4741 6C-7WAB0XK3JCSGA
00000030: 3246 3352 3850 5034 5632 4633 3556 5050 2F3R8PP4V2F35VPP
00000040: 2e45 5935 302e 464b 385a 4b4f 2f45 5a4b .EY50.FK8ZKO/EZK
00000050: 455a 3936 4c46 362f 4136 2e2e 4456 2544 EZ96LF6/A6..DV%D
00000060: 5a4a 4330 2f44 3555 4120 5145 4c50 4347 ZJC0/D5UA QELPCG
00000070: 2f44 5955 4348 5938 3355 4147 5643 2a4a /DYUCHY83UAGVC*J
00000080: 434e 4636 4634 3633 5735 4b46 3656 4636 CNF6F463W5KF6VF6
00000090: 4945 4353 4847 344b 4344 3344 5834 3742 IECSHG4KCD3DX47B
000000a0: 3436 494c 3636 3436 482a 364d 5745 574a 46IL6646H*6MWEWJ
000000b0: 4441 3641 3a39 3631 4136 5134 3745 4d36 DA6A:961A6Q47EM6
000000c0: 4224 4446 4f43 3052 3633 4b43 5a50 434e B$DFOC0R63KCZPCN
000000d0: 4636 4f46 3633 5735 2451 362b 3936 2f53 F6OF63W5$Q6+96/S
000000e0: 4135 5236 4e46 3631 4737 3335 3634 4b43 A5R6NF61G73564KC
000000f0: 2a4b 4554 4636 4134 362e 3936 3634 3642 *KETF6A46.96646B
00000100: 3536 3557 4543 2e44 3124 434b 5745 445a 565WEC.D1$CKWEDZ
00000110: 4336 5643 5334 3436 2443 3457 4555 5043 C6VCS446$C4WEUPC
00000120: 334a 4355 4941 2b45 4424 2e45 4624 444d 3JCUIA+ED$.EF$DM
00000130: 5745 3824 4342 4a45 4d56 4342 3434 3524 WE8$CBJEMVCB445$
00000140: 4342 5745 522e 4347 5043 3457 454f 5043 CBWER.CGPC4WEOPC
00000150: 4538 4648 5a41 312b 394c 5a41 5a4d 3831 E8FHZA1+9LZAZM81
00000160: 4737 3241 3632 2b38 4f47 374a 3039 5534 G72A62+8OG7J09U4
00000170: 3741 4238 5635 3954 2536 5a48 424f 3537 7AB8V59T%6ZHBO57
00000180: 5834 3852 5549 5930 3358 514f 4b2a 465a X48RUIY03XQOK*FZ
00000190: 554e 4d20 5546 5934 4435 4320 5333 5239 UNM UFY4D5C S3R9
000001a0: 5557 2d32 522a 344b 5a4a 5435 4d20 4d49 UW-2R*4KZJT5M MI
000001b0: 4d3a 3033 524d 5a4e 4120 4c4b 544f 3334 M:03RMZNA LKTO34
000001c0: 5041 2e48 3531 3936 3650 5330 4b41 502d PA.H51966PS0KAP-
000001d0: 4b4c 5048 2e51 3624 4b53 544a 302d 4736 KLPH.Q6$KSTJ0-G6
000001e0: 3538 524c 3548 5231 0a 58RL5HR1.
En l’état les données utiles sont illisibles. Nous allons maintenant voir comment tout cela est structuré.
II.3 Du binaire à la données utiles
II.3.1 Logique de la structure des données
Les données exploitables et visibles sont stockées en format JSON intégrées dans un objet de type CBOR (Concise Binary Object Representation). Celui ci est lui-même intégré dans un objet de type COSE (CBOR Object Signature and Encryption) et enfin cet objet COSE est compressé (ZLIB) puis encodé en base 45.
La donnée binaire plus haut est donc est un objet de type « COSE » encodé en base45 et compressé.
II.3.2 Récupération de l’objet « COSE »
Nous allons maintenant décoder la donnée encodée en base 45 :
zbarimg --raw --quiet qr_image.jpg | cut -b5- | base45 -d
Ce qui donne les données compressées suivantes :
00000000: 78da 013a 01c5 fed2 844d a201 2604 4853 x..:.....M..&.HS
00000010: 9bef 0779 360a 3ea0 58e5 a401 6246 5206 ...y6.>.X...bFR.
00000020: 1a60 c744 f604 1a60 cb39 7639 0103 a101 .`.D...`.9v9....
00000030: a463 7665 7265 312e 322e 3163 6e61 6da2 .cvere1.2.1cnam.
00000040: 6266 6e64 5465 7374 6366 6e74 6454 4553 bfndTestcfntdTES
00000050: 5463 646f 626a 3230 3039 2d30 322d 3238 Tcdobj2009-02-28
00000060: 6174 81a9 6274 6769 3834 3035 3339 3030 at..btgi84053900
00000070: 3662 7474 6a4c 5032 3137 3139 382d 3362 6bttjLP217198-3b
00000080: 6d61 6333 3435 6273 6374 3230 3231 2d30 mac345bsct2021-0
00000090: 342d 3133 5431 343a 3230 3a30 305a 6274 4-13T14:20:00Zbt
000000a0: 7269 3236 3034 3135 3030 3062 7463 6e43 ri260415000btcnC
000000b0: 656e 7472 6520 6465 2074 6573 7462 636f entre de testbco
000000c0: 6246 5262 6973 7645 6d65 7474 6575 7220 bFRbisvEmetteur
000000d0: 6475 2063 6572 7469 6669 6361 7462 6369 du certificatbci
000000e0: 781d 5552 4e3a 5556 4349 3a30 313a 4652 x.URN:UVCI:01:FR
000000f0: 3a47 4744 3831 4141 4831 3641 5a23 3858 :GGD81AAH16AZ#8X
00000100: 401d 93c3 17dd c28b 7d96 bb58 f3b8 25ad @.......}..X..%.
00000110: 5fda 1ccb eefe 1727 269a 9c86 af04 9264 _......'&......d
00000120: 07d2 b2c8 5348 a209 1c10 5383 2ab4 310c ....SH....S.*.1.
00000130: e1e7 529e a582 8af3 3432 e125 0374 326f ..R.....42.%.t2o
00000140: d700 876f f95f ...o._
A ce stade la donnée est compressée … décompressons là :
zbarimg --raw --quiet qr_image.jpg | cut -b5- | base45 -d | zlib-flate -uncompress
Ce qui donne les données binaires de l’objet COSE suivant :
00000000: d284 4da2 0126 0448 539b ef07 7936 0a3e ..M..&.HS...y6.>
00000010: a058 e5a4 0162 4652 061a 60c7 44f6 041a .X...bFR..`.D...
00000020: 60cb 3976 3901 03a1 01a4 6376 6572 6531 `.9v9.....cvere1
00000030: 2e32 2e31 636e 616d a262 666e 6454 6573 .2.1cnam.bfndTes
00000040: 7463 666e 7464 5445 5354 6364 6f62 6a32 tcfntdTESTcdobj2
00000050: 3030 392d 3032 2d32 3861 7481 a962 7467 009-02-28at..btg
00000060: 6938 3430 3533 3930 3036 6274 746a 4c50 i840539006bttjLP
00000070: 3231 3731 3938 2d33 626d 6163 3334 3562 217198-3bmac345b
00000080: 7363 7432 3032 312d 3034 2d31 3354 3134 sct2021-04-13T14
00000090: 3a32 303a 3030 5a62 7472 6932 3630 3431 :20:00Zbtri26041
000000a0: 3530 3030 6274 636e 4365 6e74 7265 2064 5000btcnCentre d
000000b0: 6520 7465 7374 6263 6f62 4652 6269 7376 e testbcobFRbisv
000000c0: 456d 6574 7465 7572 2064 7520 6365 7274 Emetteur du cert
000000d0: 6966 6963 6174 6263 6978 1d55 524e 3a55 ificatbcix.URN:U
000000e0: 5643 493a 3031 3a46 523a 4747 4438 3141 VCI:01:FR:GGD81A
000000f0: 4148 3136 415a 2338 5840 1d93 c317 ddc2 AH16AZ#8X@......
00000100: 8b7d 96bb 58f3 b825 ad5f da1c cbee fe17 .}..X..%._......
00000110: 2726 9a9c 86af 0492 6407 d2b2 c853 48a2 '&......d....SH.
00000120: 091c 1053 832a b431 0ce1 e752 9ea5 828a ...S.*.1...R....
00000130: f334 32e1 2503 7432 6fd7 .42.%.t2o.
On commence à apercevoir des données…
II.3.3 Analyse de l’objet COSE
Nous avons donc un objet COSE qui se lit comme un objet CBOR. La particularité de ce type d’objet est de pouvoir signer un contenu et/ou de le chiffrer.
Un objet COSE peut être de 6 types différents :
+-------+---------------+---------------+---------------------------+
| CBOR | cose-type | Data Item | Semantics |
| Tag | | | |
+-------+---------------+---------------+---------------------------+
| 98 | cose-sign | COSE_Sign | COSE Signed Data Object |
| 18 | cose-sign1 | COSE_Sign1 | COSE Single Signer Data |
| | | | Object |
| 96 | cose-encrypt | COSE_Encrypt | COSE Encrypted Data |
| | | | Object |
| 16 | cose-encrypt0 | COSE_Encrypt0 | COSE Single Recipient |
| | | | Encrypted Data Object |
| 97 | cose-mac | COSE_Mac | COSE MACed Data Object |
| 17 | cose-mac0 | COSE_Mac0 | COSE Mac w/o Recipients |
| | | | Object |
+-------+---------------+---------------+---------------------------+
Le type est renseigné dans le 1er octet dans le flux de donnés qui compose l’objet COSE. Pour nous c’est la valeur d2.
Or la donnée D2 ne correspond pas à une des valeurs « CBOR Tag ». Pour comprendre comment sont encodées les informations dans un CBOR il est nécessaire de lire les spécifications dédiées à cet objet : https://datatracker.ietf.org/doc/html/rfc7049#section-2.
Dans l’idée, pour un octet encodé il y a 2 informations stockées : sur les 3 premiers bits un type est renseigné (Major type) et sur les bits restants des informations additionnelles.
Donc notre information « D2 » en binaire correspond à 11010010 soit :
- 110 pour le Major Type : 6 en décimal cela correspond à une donnée de type « optional semantic tagging of other major types »
- le type est non assigné (cf spécification) ;
- comme nous sommes sur un objet COSE, cela correspond au type de COSE. le type d’attribut étant « ALG » ;
- 10010 pour les données additionnelles qui correspond à la valeur décimale 18 ;
- la valeur 18 que l’on retrouve dans le tableau de types de COSE et qui indique que ce COSE comporte de la donnée avec une signature.
Ainsi, dans notre cas cet objet COSE doit comporter :
- une entête (protégée et non protégée) ;
- un payload, ou le contenu (ici l’objet CBOR recherché) ;
- une signature.
Nous allons continuer à décoder manuellement les données…
La donnée suivante est « 84 » :
00000000: d284 4da2 0126 0448 539b ef07 7936 0a3e ..M..&.HS...y6.>
Donc 84 donne 10000100 soit une major type 4 (100b) et des données additionnelles indiquant 4 (00100b) : Cela indique un tableau (Major Type 4) de taille 4 (données additionnelles).
La donnée suivante est « 4d » :
00000000: d284 4da2 0126 0448 539b ef07 7936 0a3e ..M..&.HS...y6.>
Donc 4d donne 01001101 soit 010 qui indique un type de données bytes (Major type 010 soit 4) avec une taille de 13 octets (données additionnelles 01101b soit 13).
Ainsi la prochaine séquence consiste à récupérer les 13 octets suivants :
00000000: d284 4da2 0126 0448 539b ef07 7936 0a3e ..M..&.HS...y6.>
00000010: a058 e5a4 0162 4652 061a 60c7 44f6 041a .X...bFR..`.D...
00000020: 60cb 3976 3901 03a1 01a4 6376 6572 6531 `.9v9.....cvere1
00000030: 2e32 2e31 636e 616d a262 666e 6454 6573 .2.1cnam.bfndTes
En CBOR ces données n’ont pas de signification. Mais pour rappel nous sommes dans un objet COSE. Et là cette donnée « A201260448539BEF0779360A3E » correspond à l’entête protégée (Voir les spécifications CBOR) Le document européen §2.4 indique la raison et l’utilité de cette valeur : hash d’une clef de chiffrement tronqué sur 8 octets. Cette information est nommée Kid ou Key Identification. Nous vérrons dans le paragraphe ‘vérification d’un QR-Code » comment utiliser ce type de données.
Pour continuer la lecture du document il suffit d’appliquer le même principe, ce qui donne les blocs suivants:
00000000: d284 4da2 0126 0448 539b ef07 7936 0a3e ..M..&.HS...y6.>
00000010: a058 e5a4 0162 4652 061a 60c7 44f6 041a .X...bFR..`.D...
00000020: 60cb 3976 3901 03a1 01a4 6376 6572 6531 `.9v9.....cvere1
00000030: 2e32 2e31 636e 616d a262 666e 6454 6573 .2.1cnam.bfndTes
00000040: 7463 666e 7464 5445 5354 6364 6f62 6a32 tcfntdTESTcdobj2
00000050: 3030 392d 3032 2d32 3861 7481 a962 7467 009-02-28at..btg
00000060: 6938 3430 3533 3930 3036 6274 746a 4c50 i840539006bttjLP
00000070: 3231 3731 3938 2d33 626d 6163 3334 3562 217198-3bmac345b
00000080: 7363 7432 3032 312d 3034 2d31 3354 3134 sct2021-04-13T14
00000090: 3a32 303a 3030 5a62 7472 6932 3630 3431 :20:00Zbtri26041
000000a0: 3530 3030 6274 636e 4365 6e74 7265 2064 5000btcnCentre d
000000b0: 6520 7465 7374 6263 6f62 4652 6269 7376 e testbcobFRbisv
000000c0: 456d 6574 7465 7572 2064 7520 6365 7274 Emetteur du cert
000000d0: 6966 6963 6174 6263 6978 1d55 524e 3a55 ificatbcix.URN:U
000000e0: 5643 493a 3031 3a46 523a 4747 4438 3141 VCI:01:FR:GGD81A
000000f0: 4148 3136 415a 2338 5840 1d93 c317 ddc2 AH16AZ#8X@......
00000100: 8b7d 96bb 58f3 b825 ad5f da1c cbee fe17 .}..X..%._......
00000110: 2726 9a9c 86af 0492 6407 d2b2 c853 48a2 '&......d....SH.
00000120: 091c 1053 832a b431 0ce1 e752 9ea5 828a ...S.*.1...R....
00000130: f334 32e1 2503 7432 6fd7 .42.%.t2o.
Nous avons donc nos 4 sections de l’objet COSE:
- l’entête protégée ;
- l’entête en clair (vide dans notre cas) ;
- le payload (l’objet CBOR recherché) ;
- la signature.
III Lecture de l’objet CBOR (données utiles concernant le pass sanitaire)
Les données utiles sont dans le payload. Cette donnée est sous format CBOR.
III.1 Données binaires du CBOR
Ainsi les données utiles sont les suivantes :
A401624652061A60C744F6041A60CB3976390103A101A46376657265312E322E31636E616DA262666E645465737463666E74645445535463646F626A323030392D30322D3238617481A9627467693834303533393030366274746A4C503231373139382D33626D616333343562736374323032312D30342D31335431343A32303A30305A627472693236303431353030306274636E43656E747265206465207465737462636F62465262697376456D6574746575722064752063657274696669636174626369781D55524E3A555643493A30313A46523A47474438314141483136415A2338
III.2 Décodage du CBOR
Sans décoder à la main et après être passé via un parseur CBOR en ligne nous obtenons les données lisibles suivantes:
{1: "FR", 6: 1623672054, 4: 1623931254, -260: {1: {"ver": "1.2.1", "nam": {"fn": "Test", "fnt": "TEST"}, "dob": "2009-02-28", "t": [{"tg": "840539006", "tt": "LP217198-3", "ma": "345", "sc": "2021-04-13T14:20:00Z", "tr": "260415000", "tc": "Centre de test", "co": "FR", "is": "Emetteur du certificat", "ci": "URN:UVCI:01:FR:GGD81AAH16AZ#8"}]}}}
Nous avons donc la structure JSON binaire suivante (non correcte pour les 4 premières lignes du point de vue du format JSON standard car les chiffres doivent être entre guillemet) :
{
1: "FR",
4: 1623931254,
6: 1623672054,
-260: {
"1": {
"ver": "1.2.1",
"nam": {
"fn": "Test",
"fnt": "TEST"
},
"dob": "2009-02-28",
"t":
[{
"tg": "840539006",
"tt": "LP217198-3",
"ma": "345",
"sc": "2021-04-13T14:20:00Z",
"tr": "260415000",
"tc": "Centre de test",
"co": "FR",
"is": "Emetteur du certificat",
"ci": "URN:UVCI:01:FR:GGD81AAH16AZ#8"
}]
}
}
}
Cette architecture des données est spécifiée dans les document européens et qui doit prendre la forme suivante (cf lien, chapitre 2.6.3) :

III.3 Les données utiles dans le CBOR
Ainsi en bleu les données utiles dans le JSON plus haut.
Pour connaître la signification des clés/valeurs il faut se référer aux spécifications EU dont ce lien spécifie le nom des champs utilisés dans le texte en bleu.
Ce qui donne les valeurs suivantes plus lisibles :
{
"1": { --> 1er enregistrement
"ver": "1.2.1", --> Version du schéla JSON utilisé
"nam": { --> Nom de la personne
"fn": "Test", --> Nom de famille
"fnt": "TEST" --> Nom de famille standardisé
},
"dob": "2009-02-28", --> Date de naissance
"t": --> Groupe de test
[{
"tg": "840539006", --> Maladie ou agent ciblé : 840539006 indique que c'est le COVID-19
"tt": "LP217198-3", --> Type de test utilisé : LP217198-3 indique Test immunologique rapide
"ma": "345", --> Type d'appareil de test (pour le test immunologique seulement : 345
"sc": "2021-04-13T14:20:00Z", --> Date et heure du test :le 13 avril 2021 à 14:20
"tr": "260415000", --> Résultat du test : 260415000 indique non détecté
"tc": "Centre de test", --> Centre de test
"co": "FR", --> Pays : FR indique France
"is": "Emetteur du certificat", --> Emetteur du certificat
"ci": "URN:UVCI:01:FR:GGD81AAH16AZ#8" --> Identifiant Unique du certificat
}]
}
}
A ce stade bous avons retrouvé l’ensemble des données utiles ainsi que leurs significations.
IV Avec un QR-CODE d’un vrai passe sanitaire…
Nous avons vu comment récupérer les informations utiles avec un QR-CODE de test.
Utilisons un vrai QR-Code afin de vérifier le process et de visualiser les données finales quand on est déclaré officiellement vacciné et après avoir reçu le papier « CERTIFICAT COVID NUMERIQUE EU ».
Sans reprendre tout le process de décodage, nous allons nous concentrer sur le résultat final qui donne le json suivant :
{
"v": [ --> Groupe de vaccination
{
"ci": "urn:uvci:01:FR:XXXXXXXXXXXXXX", --> Identifiant unique du certificat (j'ai modifié les valeurs...)
"co": "FR", --> Pays : France
"dn": 1, --> Nombre de doses : 1 ici (oui j'ai eu le COVID, donc une seul dose)
"dt": "2021-07-24", --> Date de la vaccination
"is": "CNAM", --> Nom de l'organisation qui a fait ce certificat : la CNAM
"ma": "ORG-100030215", --> Numéro d’autorisation du vaccin
"mp": "EU/1/20/1528", --> Numéro de produit du vaccin
"sd": 1, --> Nombre total de dose pour être complètement vacciné
"tg": "840539006", --> Maladie ou agent ciblé : 840539006 indique le COVID
"vp": "J07BX03" --> Type de vaccin : J07BX03 indique Pfizer-BioNTech
}
],
"dob": "1976-12-27", --> date de naissance
"nam": { --> Nom et prénom (j'ai modifié les valeurs...)
"fn": "MonNOM",
"gn": "MonPrénom",
"fnt": "MonNOM",
"gnt": "MonPrénom"
},
"ver": "1.3.0" --> version du schéma JSON utilisé
}
En regardant les résultats nous obtenons donc les valeurs qui sont enregistrées dans un vrai QR-CODE pour le passe sanitaire.
V Vérification du QR-CODE
V.1 Introduction
Nous allons maintenant voir comment vérifier si un QR-CODE est intègre ou non contenu valide. Pour cela il faut :
- une clef publique qui va nous permettre de vérifier le contenu du QR-Code ;
- la signature du QR-Code ;
- la donnée utile à vérifier (le payload mais c’est légèrement plus compliqué au final).
Nous avons vu que l’objet COSE récupéré comportait 3 parties utiles :
- une partie entête : qui contient le KID (Key IDdentification) – ce dernier nous indique quelle clef publique il faut utiliser ;
- une partie payload : le contenu CBOR (que nous avons vu au-dessus) ;
- une partie signature : l’information qui certifie que le contenu CBOR est vrai, c’est à dire signée par la clef privé de celui qui génère ces informations.
Les paragraphes suivants vont montrer comment récupérer la clef publique, préparer la signature (il faudra changer de format) et préparer le message à vérifer (utilisation d’une structure particulière. Une fois ces 3 éléments en possession nous pourrons alors vérifier avec OpenSsl l’intégrité des informations ou non.
V.2 Récupération de la clef publique
V.2.1 Partie entête : récupération du Key Identifier (Kid)
Il est spécifié dans le document (paragraphe 2.6.1 et 2.6.2) que l’entête protégée ou non peut être utilisée pour y stocker l’information « KID ». De plus le format est du type suivant :

Donc dans notre cas, l’entête est la suivante :
D2 # tag(18)
84 # array(4)
4D # bytes(13)
A20448D6FC694CB81CEB0B0126 # "\xA2\x04H\xD6\xFCiL\xB8\x1C\xEB\v\x01&"
Ainsi pour la valeur d’entête « A20448D6FC694CB81CEB0B0126 » nous avons :
A2 # map(2)
04 # unsigned(4) --> champ Kid
48 # bytes(8)
D6FC694CB81CEB0B # "\xD6\xFCiL\xB8\x1C\xEB\v" --> valeur Kid
01 # unsigned(1) --> champ alg
26 # negative(6)
Le KID est donc « D6FC694CB81CEB0B« . Attention ce kid vient d’un QR-code de test et nous ne pourrons pas retrouver la clef publique d’un état membre.
Maintenant si on prend une entête d’un vrai QR-Code :
A2 # map(2)
01 # unsigned(1)
26 # negative(6)
04 # unsigned(4)
48 # bytes(8)
7C62EEBE0EA7E709 # "|b\xEE\xBE\x0E\xA7\xE7\t"
le KID est « 7C62EEBE0EA7E709 ». Attention il est codé en base64, donc en texte :
echo "7C62EEBE0EA7E709" | xxd -r -p | base64
Ce qui nous donne : « fGLuvg6n5wk=«
V.2.2 Clef publique
V.2.2.1 Récupération de la clef publique
Maintenant que nous avons le « Key Identifier » de la clef publique, nous pouvons récupérer la clef publique qui va nous permettre de savoir si ce QR-Code est intègre ou non dans son contenu.
Un projet Github rescence l’ensemble des clefs publiques utilisées par les états-membres :
- site github : https://github.com/lovasoa/sanipasse/
- lien ressource json qui contient les clefs : https://github.com/lovasoa/sanipasse/blob/master/src/assets/Digital_Green_Certificate_Signing_Keys.json
Donc pour trouver la clef publique qui a été utilisée il faut rechercher dans le fichier « Digital_Green_Certificate_Signing_Keys.json ». Ainsi pour le « Kid » ayant la valeur « fGLuvg6n5wk= » nous retrouvons le certificat suivant :
"fGLuvg6n5wk=": {
"serialNumber": "3563bbfbfda59864064f571ea79a5eb5fb0e1687",
"subject": "C=FR, O=CNAM, OU=180035024, CN=DSC_FR_019",
"issuer": "C=FR, O=Gouv, CN=CSCA-FRANCE",
"notBefore": "2021-06-14T22:00:00.000Z",
"notAfter": "2023-06-14T22:00:00.000Z",
"signatureAlgorithm": "RSASSA-PKCS1-v1_5",
"fingerprint": "2d53de4c89a1f5a5a901312e8ffe7e1c5573a852",
"publicKeyAlgorithm": {
"hash": {
"name": "SHA-256"
},
"name": "ECDSA",
"namedCurve": "P-256"
},
"publicKeyPem": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEImIFaugzwB5f/VyfQ3KTfTSoukwAPVSgHZWrtrc2j4FuAUpw/ObRnA9pBjN/HdUc1zcl9SO/vsCEnHkXhxjz4Q=="
}
La valeur de la clef publique est dans le champ « publicKeyPem ».
V.2.2.2 Création du fichier de la clef publique
Pour traiter des fichiers JSON via le shell nous allons utiliser le package « jq » :
sudo apt install jq
Pour plus d’informations sur ce package :
- projet officiel : https://stedolan.github.io/jq/
- exemples d’utilisation : https://blog.lecacheur.com/2016/02/16/jq-manipuler-du-json-en-shell/
Dans un premier temps nous allons récupérer le fichier :
# téléchargement du fichier JSON
wget https://raw.githubusercontent.com/lovasoa/sanipasse/master/src/assets/Digital_Green_Certificate_Signing_Keys.json
Puis à partir de ce fichier, nous créoons un fichier contenant la clef publique qui nous intéresse :
echo "-----BEGIN PUBLIC KEY-----" > public_key.pem
cat Digital_Green_Certificate_Signing_Keys.json | jq --raw-output --arg kid "fGLuvg6n5wk=" '.[$kid].publicKeyPem' >> public_key.pem
echo "-----END PUBLIC KEY-----" >> public_key.pem
Ce qui nous donne le fichier public_key.pem avec le contenu suivant :
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEImIFaugzwB5f/VyfQ3KTfTSoukwAPVSgHZWrtrc2j4FuAUpw/ObRnA9pBjN/HdUc1zcl9SO/vsCEnHkXhxjz4Q==
-----END PUBLIC KEY-----
et pour vérifier :
openssl asn1parse -in public_key.pem -inform PEM
0:d=0 hl=2 l= 89 cons: SEQUENCE
2:d=1 hl=2 l= 19 cons: SEQUENCE
4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
23:d=1 hl=2 l= 66 prim: BIT STRING
V.3 Récupération et traitement de la signature du QR-CODE
V.3.1 Avant de commencer
Comme le spécifie le document européen, l’algorithme de signature utilise l' »ECDSA w/ SHA-256″

Dans la spécification COSE utilisant une signature de type ECDSA le format de signature suit la règle suivante : la signature est la concaténation des 2 entiers de même longueur produit par l’algorithme de signature ( document). Ces entiers sont nommés R et S. Extrait :

Certains évoquent que ce type de signature correspond au format P1363.
On remarque également (en dessous du bloc orange) que la taille des chiffres R et S est déterminée en fonction de la taille de la clef publique. Ainsi pour une clef de 256bytes alors la taille de la signature sera de 64 octets (R et S respectivement sur 32 octets).
Ainsi dans le QR-Code la taille de la signature fait 64 bytes ce qui correspond au principe énoncé juste au dessus.
Mais pourquoi aller dans ce niveau de détail ? Parce que OpenSSL ne comprend pas ce format de signature. Il utilise à la place le format DER. Donc pour passer du format initial au format DER il faut savoir extraire R et S pour générer une fichier signature au format DER ( lien vers spécification (ITU-T X.690) et code des types sur wikipedia et autre lien vers µsoft).
Nous allons maintenant voir en détail comment créer un fichier de signature équivalent (format DER) et utilisable par OpenSSL.
V.3.2 Création d’un fichier de signature lisible par Openssl (format DER)
La signature renseignée dans le QR-CODE est la suivante :
FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83AADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E
Elle est composée de 2 chiffres (signatures), notées respectivement R et S. Elles sont de tailles identiques et simplement concaténées. Donc les valeurs R et S sont :
R : FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83A
S : ADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E
Dans le format DER la structure binaire à créer sera du type suivant :
Type de données | Valeur HEX | Commentaires
------------------------------------------------------------------------------------------------------------------------
Type_de_structure | 30 | indique que c'est une séquence ...
Longueur totale | 44 | longueur de ce qui suit (calculé à la fin ...)
Type_de_donnés | 02 | le type est "Integer"
Longueur de_la_donnée | 20 | taille de la valeur qui suit (20 en hex = 32 en décimal)
Valeur_de_la_donnée | FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83A | valeur R
Type_de_données | 02 | le type est "Integer"
Longueur_de_la_donnée | 20 | taille de la valeur qui suit
Valeur_de_la_donnée | ADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E | valeur S
Pour le calcul de la longueur totale, il est effectuée de la manière suivante :
Champs taille
--------------------------------------------------------------
Type de données : 1 octet
Longueur de la donnée : 1 octet
la donnée : 32 octets
Type de données : 1 octet
Longueur de la donnée : 1 octet
la donnée : 32 octets
Soit au total : 68 octets --> soit 44 en Hexadécimal :)
Donc au final la signature au format DER sera le contenu suivant :
30440220FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83A0220ADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E
Pour créer le fichier on utilisera la commande suivante :
echo -n "30440220FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83A0220ADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E" | xxd -r -p > signature.der
Pour vérifier le fichier :
openssl asn1parse -in signature.der -inform DER
0:d=0 hl=2 l= 68 cons: SEQUENCE
2:d=1 hl=2 l= 32 prim: INTEGER :-05C79A105010744EAABB673D00EEFEFAA7D9A1D4887F8BDA7855FDCBD0C227C6
36:d=1 hl=2 l= 32 prim: INTEGER :-521793FC2D9820F3CC7BAD3837E8EB0DC8619300A730F0A4B2F32AF141433192
Et cela ne fonctionne pas 🙁 🙁 🙁 Nous ne retrouvons pas nos clefs initiales et de plus elles sont négatives …
En effet dans certains cas il faut ajouter un 00 devant les chiffres R et S. Le format DER utilise le principe du complément à 2 pour les chiffres entiers. Dans notre cas les résultats R et S sont des chiffres positifs. En revanche R commence par FA… et S par AD… ce qui en binaire représente respectivement 11111010 et 10101101. Au format DER et comme le premier bit est à 1, ces chiffres seront considérés comme négatif. Il faut donc ajouter un 0 devant soit 00 en hexadécimal.
Donc notre nouvelle signature comprenant le recalcul des tailles sera :
3046022100fa3865efafef8bb1554498c2ff11010558265e2b7780742587aa02342f3dd83a022100ade86c03d267df0c338452c7c81714f2379e6cff58cf0f5b4d0cd50ebebcce6e
Ainsi la commande shell pour générer le nouveau fichier de signature :
echo -n "3046022100fa3865efafef8bb1554498c2ff11010558265e2b7780742587aa02342f3dd83a022100ade86c03d267df0c338452c7c81714f2379e6cff58cf0f5b4d0cd50ebebcce6e" | xxd -r -p > signature.der
On vérifie :
openssl asn1parse -in signature2.der -inform DER
0:d=0 hl=2 l= 70 cons: SEQUENCE
2:d=1 hl=2 l= 33 prim: INTEGER :FA3865EFAFEF8BB1554498C2FF11010558265E2B7780742587AA02342F3DD83A
37:d=1 hl=2 l= 33 prim: INTEGER :ADE86C03D267DF0C338452C7C81714F2379E6CFF58CF0F5B4D0CD50EBEBCCE6E
Et là c’est bon, nous retrouvons les valeurs R et S au format DER 🙂 ainsi qu’un fichier de signature compréhensible par OpenSSL.
V.4 Données à valider
Nous entrons dans la dernière étape avant de vérifier le QR-Code : la donnée à valider. On pourrait croire que le contenu du CBOR (payload) serait suffisant. Mais non, d’après les spécifications du COSE (lien) la vérification se fait avec une structure CBOR spécifique (nommée Sig_Structure) dont la structure doit être la suivante :
Sig_structure = [
context : "Signature" / "Signature1" / "CounterSignature", --> vu le type de COSE se sera Signature1
body_protected : empty_or_serialized_map, --> le header du QR-COde
? sign_protected : empty_or_serialized_map, --> rien
external_aad : bstr, --> champ non utilisé dans le COSE, donc valeur vide
payload : bstr --> le payload ou CBOR
]
Ainsi notre CBOR spécifique sera de la forme et avec le contenu suivant :
[
"Signature1",
h'A2012604487C62EEBE0EA7E709',
h'',
h'A40164434E414D041A6488E6E0061A60FC5959390103A101A4617681AA626369781D75726E3A757663693A30313A46523A4B564A5059574D5342314256233862636F62465262646E016264746A323032312D30372D323462697364434E414D626D616D4F52472D313030303330323135626D706C45552F312F32302F313532386273640162746769383430353339303036627670674A30374258303363646F626A313937362D31322D3237636E616DA462666E6548454E525962676E6658415649455263666E746548454E525963676E74665841564945526376657265312E332E30'
]
En utilisant un outil en ligne nous re-construisons le CBOR binaire à partir du tableau « Sig_structure » renseigné. Ce qui nous donne le résultat ci-dessus :
846A5369676E6174757265314DA2012604487C62EEBE0EA7E7094058E2A40164434E414D041A6488E6E0061A60FC5959390103A101A4617681AA626369781D75726E3A757663693A30313A46523A4B564A5059574D5342314256233862636F62465262646E016264746A323032312D30372D323462697364434E414D626D616D4F52472D313030303330323135626D706C45552F312F32302F313532386273640162746769383430353339303036627670674A30374258303363646F626A313937362D31322D3237636E616DA462666E6548454E525962676E6658415649455263666E746548454E525963676E74665841564945526376657265312E332E30
Enfin, nous pouvons maintenant créer ce fichier en shell :
echo "846A5369676E6174757265314DA2012604487C62EEBE0EA7E7094058E2A40164434E414D041A6488E6E0061A60FC5959390103A101A4617681AA626369781D75726E3A757663693A30313A46523A4B564A5059574D5342314256233862636F62465262646E016264746A323032312D30372D323462697364434E414D626D616D4F52472D313030303330323135626D706C45552F312F32302F313532386273640162746769383430353339303036627670674A30374258303363646F626A313937362D31322D3237636E616DA462666E6548454E525962676E6658415649455263666E746548454E525963676E74665841564945526376657265312E332E30" | xxd -r -p > data.bin
V.5 Vérification (avec OpenSSL)
A ce stade nous avons tout ce qu’il faut pour effectuer la vérification (intégrité) du QR-CODE, c’est à dire :
- la clef publique ;
- la signature au format DER ;
- la donnée à vérifier (CBOR spécifique) ;
Nous pouvons maintenant lancer cette vérification du QRCODE en utilisant l’outil OPENSSL en shell :
openssl dgst -sha256 -verify public_key.pem -signature signature.der data.bin
Verified OK
Et, après tout ce labeur, nous remarqons que le contenu du QR-Code est bien intègre (non modifié) !
V.6 Ressources
Ci-dessous les ressources qui ont permis de comprendre la partie vérification du QR-Code
- site expliquant dir KID key Identification présent dans le CBOR vers la clef publique
- http://www.corentindupont.info/blog/posts/Programming/2021-08-13-GreenPass.html
VI Fin
VI.1 Constat simple
Nous pouvons maintenant voir précisément ce que comporte à ce jour ce type de QR-CODE. Bref peu d’informations et juste le nécessaire pour dire si une personne (nom, prénom et date de naissance) est vaccinée ou pas (par qui et quel type de vaccin).
VI.2 Modification du JSON et création d’un autre QR-Code
Mais que se passe-t-il si on modifie une valeur et que l’on applique le process inverse (en gardant les informations initiales de la signature et de l’entête protégée) ? Comme par exemple changer le nom. Hé bien, avec l’application « Tous anti covid verif », le QR-CODE est déclaré invalide. En revanche l’application affiche le nom, prénom et date de naissance indiqués dans le QR-CODE modifié. C’est rassurant car l’application vérifie la signature du QR-Code qui est fausse pour ce cas.
Ci-dessous un exemple pour générer un QR-CODE :
cat final_modif_COSE_HEX_compress_base45_HC1.txt | qrencode -o qr_code.png # Génère l'image d'un QR-Code à partir de données binaires
display qr_code.png # Affiche le QR-CODE
VI.3 Mais peut-on créer un vrai/faux QR-CODE ?
Oui dans l’absolu et non ou très difficile en pratique. L’application « Tous anti-covid vérif » utilise une clef publique pour vérifier la signature car cette dernière ne communique pas sur le réseau d’après les informations données sur l’appli (à vérifier…). Elle est donc autonome pour vérifier le QR-Code. Mais la clef publique ne permet pas de générer une signature, juste de la vérifier. Il faut une clef privée pour cela. Le processus pour retrouver la clef privée peut être très (très) long mais pas impossible en soi… Par contre pour récupérer la clef publique, ce serait assez facile en récupérant l’APK de l’application android elle est disponible sur Internet (cf. au dessus) et pourquoi pas voir comment faire la vérification de la signature soi-même.
Dans le pire des cas, on pourrait imaginer que des tests complémentaires soient effectués avec le numéro unique du certificat. Il suffirait ensuite de comparer ce numéro avec le nom, prénom et date de naissance de l’individu. Et là, la supercherie pourra être détectée mais cela nécessite une connexion sur un serveur dédié. Il semble que ce ne soit pas le cas aujourd’hui avec l’application française mais c’est tout à fait envisageable demain si le besoin s’en faisait sentir et ce de manière relativement simple. Peut être que d’autres applications européennes font cette vérification… C’est peut être fait avec l’application « Tous anti-covid ». Les sources (une partie) viennent d’être publiées sur le gitlab de l’Inria et son étude pourra infirmer ou confirmer ce point.
VI.4 Données en clair, pas chiffrées ?
Pour ma part, en découvrant les objets binaires CBOR et surtout COSE, on remarque que les informations auraient pu être chiffrées, ce qui n’est pas le cas aujourd’hui. Or, dans le cadre de protection des données des individus et au regard des informations de type médical cela aurait été sûrement mieux. Est-ce lié à la limitation du nombre de caractères possibles dans le QR-Code ou à la complexité organisationnelle pour mettre en place un outil plus technique utilisable par plusieurs de type de population afin qu’elles puissent vérifier le QR-Code (ex : restaurateur, cinémas, etc.) ? Cette dernière hypothèse semble plus probable.
VI.5 L’application « TousAntiCovid verif »
Au téléchargement de l’application il est stipulé que « L’usage de l’application TousAntiCovid est réservé aux personnes habilitées et services autorisés dans le cadre de la loi n°2021-689 […]« . Et que si l’on est pas éligible à l’utilisation de cette application on encoure des sanctions …
Pour être plus précis, l’application n’est pas citée dans la loi. En revanche il est stipulé dans l’article 1 :
- « B. – La présentation du résultat d’un examen de dépistage virologique ne concluant pas à une contamination par la covid-19, d’un justificatif de statut vaccinal concernant la covid-19 ou d’un certificat de rétablissement à la suite d’une contamination par la covid-19 dans les cas prévus au A du présent II peut se faire sur papier ou sous format numérique. La présentation, sur papier ou sous format numérique, des documents mentionnés au premier alinéa du présent B est réalisée sous une forme ne permettant pas aux personnes habilitées ou aux services autorisés à en assurer le contrôle de connaître la nature du document ni les données qu’il contient. »
- « C. – Les personnes habilitées et nommément désignées et les services autorisés à contrôler les documents mentionnés aux 1° et 2° du A pour les sociétés de transport et les lieux, établissements ou événements concernés ne peuvent exiger leur présentation que sous les formes prévues au second alinéa du B et ne sont pas autorisés à les conserver ou à les réutiliser à d’autres fins. Le fait de conserver les documents mentionnés aux 1° et 2° du A dans le cadre du processus de vérification ou de les réutiliser à d’autres fins est puni d’un an d’emprisonnement et de 45 000 € d’amende.«
- « D. – Hors les cas prévus aux 1° et 2° du A, nul ne peut exiger d’une personne la présentation d’un résultat d’un examen de dépistage virologique ne concluant pas à une contamination par la covid-19, d’un justificatif de statut vaccinal concernant la covid-19 ou d’un certificat de rétablissement à la suite d’une contamination par la covid-19. Est puni d’un an d’emprisonnement et de 45 000 € d’amende le fait d’exiger la présentation des documents mentionnés au premier alinéa du présent D pour l’accès à d’autres lieux, établissements ou événements que ceux mentionnés au 2° du A. »
Donc nous pouvons utiliser l’application pour lire son propre QR-code, pas ceux des autres !