Hogy működik a digitális Covid igazolvány?

És miért “írja át” az utolsó oltás az előzőket?

Bevezető

Néhány hete a hónapok óta bennem ketyegő műhold kapott egy kis processzor frissítést: két Sputnik V után kértem egy Comirnaty ismétlőt. Bevallom, ennek elsődleges oka nem a védettség növelése volt, hanem a korábban felröppenő hírek [1], hogy az EU-s igazolványban a harmadik oltás “átírja” az első kettőt is. Csábító volt, hogy újra teszt nélkül tévedhessek át a határon Írottkőnél, vagy Ausztrián keresztül tekerhessek le Gotthárdra.

Ezzel együtt persze kíváncsi voltam, hogy mi az oka annak, hogy így működik az igazolvány, egyáltalán hogyan működik, és persze az is érdekelt, hogy kell-e számítanom a kiskapu bezárására. Következő lépés: a nyúl ürege… A fura működés oka hamar egyértelmű lett, de ha már nekiálltam, át szerettem volna látni az egész rendszert – legalább nagyvonalakban. Egy kupac PDF elolvasása és GitHub repo átböngészése után pedig itt vagyok, hogy zanzásítva megosszam az összeszedett információt. Itt azért megjegyzem, hogy igen, jól látjátok, GitHub repókat írtam, ugyanis a rendszer minden komponenséhez létezik egy nyílt forrású, bárki számára elérhető referencia implementáció [2]. Őszintén szólva nekem ez, és a letölthető dokumentációk [3] mennyisége és részletessége is kellemes meglepetés volt.

Az igazolványt itthon az EESZT rendszeréből tölthetjük le [4], és minden megkapott oltáshoz külön PDF tartozik.

A dokumentumon az oltás, illetve az oltott adatai mellett egy QR-kód található. Utóbbi, mint látni fogjuk, gyakorlatilag az olvashatóan is megjelenített adatokat tartalmazza olyan formában, hogy a hitelessége (majdnem teljesen) offline módon is ellenőrizhető legyen.

Igazolvány kiállítása

Mielőtt beleássuk magunkat a QR-kódban tárolt adatokba, megpróbálom nagyvonalakban bemutatni a rendszer felépítését. Az igazolványok (Digital Green Certificate, röviden DGC) tulajdonképpen kriptográfiai módszerekkel aláírt adathalmazok az oltott/tesztelt/gyógyult személyről, illetve az oltásról/tesztről/gyógyulásról. Ezeket minden tagállam saját maga állítja ki egy alkalmazáson keresztül, ami a tagállam saját háttérrendszerével (illetve háttérrendszereivel, több is lehet) kommunikál; ez nyújtja az igazolványok létrehozásához, aláírásához szükséges szolgáltatásokat, illetve egyéb feladatokat is ellát.

Az egyéb feladatok közül a legfontosabb az, hogy elküldi, illetve frissíti a DGC-k aláírásához használt kulcsok publikus részét a Digital Green Certificate Gateway-nek (DGCG [5]). Ez utóbbiból az EU-ban egy közös van, amit a DIGIT (Directorate-General for Informatics) üzemeltet, és legfőbb feladata a neki küldött publikus kulcsok tárolása és megosztása az összes tagállammal. A DGCG egy úgynevezett trust anchor, azaz a rendszer összes többi eleme él a feltételezéssel, hogy megbízható, a megbízhatóságának igazolására azonban nincs kriptográfiai módszer. Ilyen szempontból a DGCG egy tanúsítványkiadóhoz (Certificate Authority) hasonlítható. Azt, hogy valóban csak a tagállamoktól származó publikus kulcsok kerülhessenek fel rá (ezáltal váljanak megbízhatóvá), az onboarding folyamatok szigorú szabályozásával érik el (legalábbis papíron, csakúgy, mint egy CA-nál, khm.. DigiNotar, khm.. 🙂 )

A referencia implementációk az alábbi linkeken érhetők el:
• Kiállító alkalmazás [6]
• Kiállító háttérrendszer [7]
• Gateway [8]

Hitelesség ellenőrzése

Az eddigieket összefoglalva megtudtuk, hogy az igazolványok digitálisan aláírt dokumentumok, melyeket a tagállamok állítanak ki, írnak alá egy saját rendszerrel (kiállító alkalmazás és a háttérrendszere), az aláíró kulcsok publikus részét pedig elküldik egy központi rendszerbe (DGCG), ami tovább osztja azokat a többi tagállamnak. Erre azért van szükség, hogy bármely résztvevő ország ellenőrizhesse bármely másik ország által kiállított igazolványok hitelességét.

Az ellenőrzéshez a tagállamok szabadon fejleszthetnek saját alkalmazást, de a rendszer működéséből adódóan bármely ország alkalmazásával igazolható bármely ország igazolványa. Az ellenőrző alkalmazás háttérrendszere egyetlen feladatot lát el: szinkronizálja és tárolja a DGCG publikus kulcs listáját, és megosztja azt az ellenőrző alkalmazással. Az alkalmazás köteles tárolni ezt a listát, és – ajánlottan napi egyszer – köteles frissíteni azt a háttérrendszerről. A frissítés nem csak az újonnan felkerült kulcsok letöltését jelenti, hanem a DGCG-n már nem szereplők törlését is. Az ellenőrző alkalmazásban ez az egyetlen folyamat, amihez internet kapcsolat szükséges, maga az ellenőrzés teljesen offline történik (erre utaltam korábban a majdnem teljesen offline működéssel). Fontos, hogy az offline működés nem csak egy lehetőség, hanem elvárás: az alkalmazás az igazolványok adatait nem továbbíthatja, illetve nem is tárolhatja – így a kibocsájtó szervezet nem szerezhet tudomást arról, hogy mikor és hol ellenőriznek egy általa kiadott igazolványt.

Maga az ellenőrzés úgy történik, hogy az alkalmazás beolvassa a QR-kódot, dekódolja a benne tárolt információt, és megnézi, hogy az valóban egy olyan privát kulccsal van-e aláírva, aminek a publikus párja szerepel a DGCG listájában. Az alkalmazás természetesen csak azt tudja megmondani, hogy a QR kódban tárolt adatok hitelesek-e, azt nem, hogy ténylegesen az igazolványt felmutató személyhez tartoznak-e – ez az ellenőrzést végző személy felelőssége, össze kell vetnie az alkalmazás által megjelenített személyes adatokat (név, születési dátum) az ellenőrzött személy valamilyen azonosító okmányával.

A referencia implementációk az alábbi linkeken érhetők el:

• Ellenőrző háttérrendszer [9]
• iOS ellenőrző alkalmazás [10]
• Android ellenőrző alkalmazás [11]

Igazolvány tárolása mobileszközön

Az úgynevezett Digital Green Certificate Applications (DGCA [12]) programcsomagnak eddig négy komponensét (kiállító és ellenőrző alkalmazás, illetve ezek háttérrendszere) láttuk. Ezeken kívül még egy komponens létezik, egy úgynevezett wallet alkalmazás. Ezt a programot hagytam a végére, aminek két oka van: egyrészt Magyarországnak jelenleg nincs ilyen alkalmazása (A többi DGCA komponenshez hasonlóan ebből sincs közös, minden résztvevő ország magának fejlesztheti le.), másrészt nem igazán látom az értelmét. Tulajdonképpen a célja a papíron, vagy PDF-ként kiállított igazolvány mobil eszközön való tárolása, és az adott eszközhöz való kötése (hogy más ne tudja „ellopni”, másik eszközön használni).

Ezt úgy valósítja meg, hogy az importáláshoz szükséges egy második faktor, és az alkalmazás csak akkor engedi importálni az igazolványt, ha azt még nem regisztrálták. A dokumentációkban ajánlott második faktor egy, az igazolvány létrehozásakor generált TAN (Transaction Authentication Number), amit az igazolvány tulajdonosa e-mail-ben, vagy SMS-ben kap meg. Az importáláshoz először a wallet beolvassa a QR kódot, generál egy kulcspárt, majd elküldi a kiállító alkalmazás háttérrendszerének (a wallet-nek nincs saját háttérrendszere) az igazolvány egyedi azonosítóját (Digital Green Card Identifier, DGCI), az igazolvány és a TAN SHA256 hash-ét, a generált publikus kulcsot, illetve ezeknek az aláírását. A háttérrendszer ellenőrzi, hogy a küldött TAN érvényes-e (csak egyszer lehet felhasználni), és valóban az adott DGCI-hez tartozik-e. Amennyiben a küldött adatok a feltételeknek megfelelnek, a háttérrendszer pozitív válasza után a wallet alkalmazás importálja az igazolványt, és titkosítva tárolja azt az eszközön.

Miért írtam korábban, hogy nem látom értelmét? Az alkalmazás célja tulajdonképpen az, hogy tároljon és megjelenítsen egy QR kódot, és az egész szerverrel való kommunikáció csak azért szükséges, hogy ha én megszerzem valakinek a QR kódját, akkor ne tudjam beimportálni. Mi történik, ha fejlesztek egy alkalmazást, ami ugyanúgy néz ki, mint az eredeti, és abba importálom? Az ellenőrző személy nem fogja tudni megmondani, hogy az nem az eredeti alkalmazás. Egyébként mi a támadási scenarió? Nem oltatom be magam, hanem inkább keresek valakit, akinek ugyanaz a neve és születési dátuma, mint nekem, és ellopom a QR kódját? Nem mintha nem tudnám elképzelni, hogy ez valakinek megfordul a fejében, csak szerintem ennél még akkor is nagyobb esély van a sikerre, ha valaki a privát kulcsot próbálja meg visszaszámolni. Mindezek mellett a dokumentáció nem érinti azt az esetet, ha felhasználóként szeretnék telefont cserélni. Lehet, hogy valamit félreértek ebben az egész folyamatban, de nekem nem tűnik praktikusnak ezt ennyire megbonyolítani.

A referencia implementációk az alábbi linkeken érhetők el:
• Android wallet alkalmazás [13]
• iOS wallet alkalmazás [14]

Mit tartalmaz a QR kód?

Az eddigiekből megismerhettük, hogy miként épül fel az igazolvány kiadását, ellenőrzését, tárolását megvalósító rendszer, de azt még nem tudjuk, hogy pontosan mit is tartalmaz az a bizonyos QR kód. A dokumentációból kiderül, hogy az igazolvány lényegi tartalma egy meghatározott sémát [15] követő JSON (JavaScript Object Notation [16]) dokumentum, ami a következő átalakításokon esik át, hogy QR kód legyen belőle:

Első lépésként a szöveges JSON objektumot szerializálják úgynevezett CBOR (Concise Binary Object Representation, [17]) formátumba. Ez egy olyan bináris formátum, aminek fő célja strukturált adatok minél kisebb helyen való tárolása úgy, hogy a feldolgozó kód mérete is minimális legyen.

Erre a formátumra épül az úgynevezett COSE (CBOR Object Signing and Encryption, [18]) szabvány, mely alapvető kriptográfiai megoldások (titkosítás, aláírás, MAC) használatát írja le CBOR formátum esetén. A DGC hitelességének biztosításához a tartalom digitális aláírása szükséges, így az átalakítás második lépéseként egy cose-sign1 típusú COSE üzenet jön létre, mely a tényleges tartalom mellett annak digitális aláírását is tartalmazza.

Bár a használt formátumok is törekszenek a minél kisebb méretre, a harmadik lépés a COSE üzenet tömörítése a zlib deflate [19] algoritmussal.

A tömörített adathalmaz a QR generálás előtt még átesik egy átalakításon: base45 [20]-enkódolják. A base45 algoritmust a DGC projekt során hozták létre azért, hogy a bináris adatot minél kisebb QR kóddá lehessen alakítani úgy, hogy annak beolvasása biztosan ne okozzon gondot a létező szoftvereknek.

A base45-enkódolt szöveg elejére még egy kettősponttal elválasztva hozzáfűzik az aktuális verziót, ami jelenleg „HC1”, és az eredményből készül el a végleges QR kód.

A fentiek ismeretében írható egy egyszerű script, ami kiolvassa az igazolványban tárolt adatokat:

Ezt egy példa QR kódon lefuttatva a következő kimenetet kapjuk:

Eljutottunk végre a legbelső réteghez, már csak annyi van hátra, hogy értelmezzük a JSON struktúrát. A legtöbb mezőről az értéke alapján egyértelmű, hogy micsoda, de azért van egy pár, ami csak a dokumentációból derül ki egyértelműen.

Minden igazolvány kötelezően tartalmazza az alábbi adatokat:

• kibocsátó ország kódja („1”)
• kibocsátás dátuma („6”) UNIX időbélyeg formában (1970. január 1. óta eltelt másodpercek száma)
• lejárat dátuma („4”) szintén UNIX időbélyeg formában
• HCERT JSON („-260”):
o séma verziója (“ver”, ez jelenleg 1.3.0)
o név (“nam”)
o születési dátum (“dob”)
o vakcina (“v”), teszt (“t”), vagy felépülés (“r”) adatai

Az utolsóból minden igazolvány esetén csak egy lehet (vagy egy “v”, vagy egy “t”, vagy egy “r”). A továbbiakban az oltási igazolvánnyal foglalkozom, mivel végső soron a „Miért írja át az utolsó oltás az előzőket?” kérdés miatt létezik ez a cikk 🙂

Oltási igazolvány esetén a “v” adatmezőnek kötelezően kell tartalmaznia az alábbi mezőkből egyet-egyet:

• Kórokozó azonosítója (“tg”): ennek értéke jelenleg minden igazolvány esetén a COVID-19-t jelentő 840539006.
• Vakcina, vagy kezelés típusa (“vp”): A lehetséges értékek megtalálhatók a Value Sets for for EU Digital COVID Certificates [21] dokumentum 2.2 pontjában. A példában szereplő 1119349007 érték az mRNS vakcinákat jelöli.
• Vakcina gyártmánya (“mp”): A lehetséges értékek a fenti dokumentumban [21], a 2.3-as pontban találhatók. A példában szereplő EU/1/20/1507 érték a SpikeVax-t, a Moderna vakcináját jelöli.
• Gyártó, vagy forgalomba hozatali engedély jogosultja (“ma”): A lehetséges értékek a fenti dokumentumban [21], a 2.4-es pontban találhatók. A példában szereplő ORG-100031184 érték a Moderna Biotech Spain S.L.-t jelöli.
• Beadott oltás sorszáma (“dn”): A sor hányadik oltását igazolja a DGC.
• Oltások teljes száma a sorban (“sd”): Ennyi oltásból áll a teljes oltási ciklus.
• Oltás dátuma (“dt”)
• Országkód (“co”): A vakcinát beadó ország kétbetűs kódja. Ebben a pontban eltérés van a JSON séma specifikáció [15] és a lehetséges értékeket leíró dokumentum [21] között, ugyanis az előbbi megengedi nemzetközi szervezetek (pl. WHO) kódját is értékként.
• Kibocsátó szervezet (“is”)
• Igazolvány egyedi azonosítója (“ci”): Három elfogadott formátum létezik attól függően, hogy a kibocsátó mennyi információt szeretne vele „ránézésre” átadni. Az opcionális „URN:UVCI:” előtag, a kötelező verzió, országkód, és az azonosító végén található ellenőrző kód mellett a következők valamelyikét kell tartalmaznia:
o a kibocsátó szervezetet, a vakcina típusát és egy egyedi azonosítót
o a kibocsátó szervezetet és egy egyedi azonosítót
o csak egy egyedi azonosítót.
A példában a harmadik, legegyszerűbb, legkevesebb információt eláruló azonosító látható, és a magyar igazolványok is ezt alkalmazzák.
Megjegyzés: a sémát és a lehetséges értékeket bemutató dokumentumok UVCI (Universal Certificate Identifier)-ként hivatkoznak az értékre, de ez megegyezik a többi dokumentumban DGCI (Digital Green Certificate Identifier)-nek nevezett értékkel.
A specifikáció szerint egy oltási igazolványban csak egy vakcinát leíró („v”típusú) mező lehet, és az – annak ellenére, hogy „array” típusú – csak egy elemet tartalmazhat (minItems = maxItems = 1).

A Guidelines on verifiable vaccination certificates basic interoperability elements [22] dokumentum első melléklete (amely az igazolvány minimálisan elvárt adattartalmát írja le) egyébként megenged több vakcina információ mezőt egy igazolványon belül, azonban a néhány hónappal későbbi séma definíció már egyértelműen csak egyet.

Ezek alapján látható, hogy az EU igazolvány által használt adatformátum jelenlegi, 1.3.0-ás verziója nem képes egy oltási ciklusként megfelelően kezelni azokat az eseteket, ahol az emlékeztető oltás típusa („vp”, „mp”, „ma” mezők) eltér az alapimmunizáláshoz használttól. Technikailag lehetséges lenne persze külön oltási ciklusként kezelni az emlékeztetőt – ez felhasználói szemszögből azzal járna, hogy pl. az én 2 Sputnik és 1 Comirnaty oltásom igazolásához legalább két DGC kellene: egy a második Sputnik-ról 2/2 „dn”/”sd” értékekkel , és egy az emlékeztetőről 1/1 „dn”/”sd” értékekkel. Ez persze csak a technológia adta lehetőség, abba nem látok bele, hogy a gyakorlatban mi lenne a megfelelő megoldás.

Egyetlen kérdés megválaszolása maradt hátra: be lehet zárni a kiskaput? A már kiadott igazolványok esetén a válasz az, hogy nem. Legalábbis tisztán technikai módon nem. A DGC működéséből adódóan ellenőrzéskor az oltott személy és az oltás adatai nem egy háttérrendszerből jönnek, így nem is lehetséges utólag háttérrendszeren korrigálni. Technikailag van lehetőség a kiállító kulcs érvénytelenítésére, és új igazolványok kiadására, de ez azt jelentené , hogy minden eddig kiadott igazolvány (nem csak a „hibásak”) érvényét vesztené. Ez az ajánlásokkal is szembemenne, hiszen a dokumentációk szerint – érthető módon – a kulcsnak legalább a vele aláírt DGC-k érvényességi idejéig érvényesnek kell maradnia.

Nem tudom, hogy erre végül technológiai, vagy szabályozás alapú megoldást (pl. be kell mutatni az összes igazolványt) fognak-e találni, mindenesetre kíváncsian várom, hogy más országok, illetve az egész DGC projekt milyen módon kezeli majd a heterológ oltási sorok igazolását.

Hivatkozások

[1] P. Judit, „telex,” 01 09 2021. [Online]. Available: https://telex.hu/koronavirus/2021/09/01/harmadik-oltas-vedettsegi-unios-covid-igazolvany.
[2] EU Digital COVID Certificates (EUDCC) project, [Online]. Available: https://github.com/eu-digital-green-certificates.
[3] eHealth Network, „eHealth and COVID-19,” [Online]. Available: https://ec.europa.eu/health/ehealth/covid-19_en.
[4] Elektronikus Egészségügyi Szolgáltatási Tér, „Uniós digitális Covid igazolvány Lakossági Portálon keresztül,” [Online]. Available: https://www.eeszt.gov.hu/hu/unios-digitalis-covid-igazolvany.
[5] eHealth Network, „EU Digital COVID Certificate Gateway (Technical Specifications for Digital Green Certificates vol. 2),” [Online]. Available: https://ec.europa.eu/health/sites/health/files/ehealth/docs/digital-green-certificates_v2_en.pdf.
[6] EU Digital COVID Certificates (EUDCC) project, „Issuance Web Frontend,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-issuance-web.
[7] EU Digital COVID Certificates (EUDCC) project, „Issuance Service,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-issuance-service.
[8] EU Digital COVID Certificates (EUDCC) project, „Gateway,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgc-gateway.
[9] EU Digital COVID Certificates (EUDCC) project, „Verifier Service,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-verifier-service.
[10] EU Digital COVID Certificates (EUDCC) project, „Verifier App – iOs,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-verifier-app-ios.
[11] EU Digital COVID Certificates (EUDCC) project, „Verifier App – Android,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-verifier-app-android.
[12] eHealth Network, „EU Digital COVID Certificate Applications (Technical Specifications for Digital Green Certificates vol. 4),” [Online]. Available: https://ec.europa.eu/health/sites/health/files/ehealth/docs/digital-green-certificates_v4_en.pdf.
[13] EU Digital COVID Certificates (EUDCC) project, „Wallet App – Android,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-wallet-app-android.
[14] EU Digital COVID Certificates (EUDCC) project, „Wallet App – iOS,” [Online]. Available: https://github.com/eu-digital-green-certificates/dgca-wallet-app-ios.
[15] eHealth Network, „JSON Schema for EU Digital COVID Certificates,” [Online]. Available: https://ec.europa.eu/health/sites/health/files/ehealth/docs/covid-certificate_json_specification_en.pdf.
[16] IETF, „JavaScript Object Notation,” [Online]. Available: https://datatracker.ietf.org/doc/html/rfc8259.
[17] IETF, „Concise Binary Object Representation,” [Online]. Available: https://datatracker.ietf.org/doc/html/rfc8949.
[18] IETF, „CBOR Object Signing and Encryption,” [Online]. Available: https://datatracker.ietf.org/doc/html/rfc8152.
[19] IETF, „zlib deflate,” [Online]. Available: https://datatracker.ietf.org/doc/html/rfc1951.
[20] IETF draft, „The Base45 Data Encoding,” [Online]. Available: https://datatracker.ietf.org/doc/draft-faltstrom-base45/.
[21] eHealth Network, „Value sets,” [Online]. Available: https://ec.europa.eu/health/sites/health/files/ehealth/docs/digital-green-value-sets_en.pdf.
[22] eHealth Network, „eHealth Network guidelines on verifiable vaccination certificates – basic interoperability elements,” [Online]. Available: https://ec.europa.eu/health/sites/health/files/ehealth/docs/vaccination-proof_interoperability-guidelines_en.pdf.

A JSON – QR-kód átalakítást bemutató ábra a http://www.customicondesign.com/free-icons/mono-icon-set/ ikonok felhasználásával készült.