Certificado COVID digital de la UE (EUDCC)

  • Divulgación
  • Privacidad y seguridad
  • A consecuencia de la pandemia de COVID-191, iniciada a principios de 2020, la Comisión Europea y los países de la Unión Europea definieron un marco común, uniforme e interoperable para emitir pruebas o certificados COVID. El objetivo es que esta información pueda ser reconocida por todos ellos, independientemente del país en el que cada ciudadano lo haya recibido.

    Casi dos años después, en enero de 2022, no solo todos los países de la UE se habían adscrito, sino que prácticamente toda la Europa continental e incluso algunos países de otros continentes se han sumado a la iniciativa2.

    El certificado COVID digital de la Unión Europea (en inglés EU Digital COVID Certificate, EUDCC), también conocido como Green Pass o Pasaporte COVID, es una prueba digital de que una persona ha sido vacunada contra el COVID-19, o bien se ha recuperado de la enfermedad, o simplemente ha sido testeada. Por tanto, el EUDCC en realidad hace alusión a tres tipos de certificados diferentes: vacunación, recuperación y test.

    En el portal web oficial de la Unión Europea3 podemos encontrar información adicional sobre el EUDCC. En la web de la OMS4 podemos leer el documento marco en el que se dan recomendaciones generales para este tipo de certificados.

    Cómo funciona #

    El EUDCC consiste en un código QR5 que contiene la información sanitaria del ciudadano, así como algunos datos personales (el nombre, la fecha de nacimiento, la fecha de expedición, la información pertinente sobre la vacuna, la prueba o la recuperación y un identificador único). Este QR lo puieden emitir diferentes entidades nacionales o regionales (en el caso de España las comunidades autónomas) y además han de firmarlo digitalmente con sus certificados raíz para evitar falsificaciones. Se puede llevar en una aplicación específica, pero también en una imagen en el móvil, o simplemente impreso en una hoja de papel.

    Cada país tiene la potestad de exigir, o no, el certificado COVID a cualquier viajero que entre en su territorio, y en su caso, de decidir qué pautas de vacunación, tests o recuperación de la enfermedad da por válidas, o de imponer cuarentenas, etc. En algunos países y regiones también se generalizó su uso para permitir o denegar el acceso de los ciudadanos a determinados establecimientos comerciales o de ocio.

    A la hora de comprobar la validez, existen aplicaciones web o móviles que son capaces tanto de decodificar la información como de validar su autenticidad. Algunas de ellas han sido desarrolladas por cuidadanos a título individual, y otras a iniciativa de diferentes administraciones públicas.

    El sistema está diseñado de modo que no se envía información a ninguna parte cada vez que se escanea el QR de un ciudadano, ya que tanto la decodificación como la comprobación de la autenticidad se realizan en el propio dispositivo, incluso sin necesidad de conexión a internet. Basta con que la aplicación se haya descargado previamente todas las claves públicas de las entidades certificadoras involucradas, o bien las lleve incrustadas en su código.

    Sin embargo debemos tener cuidado, porque no podemos estar seguros de que quien esté escaneando los códigos no esté almacenando toda esta información en su propio dispositivo. Las aplicaciones oficiales suelen tener su código abierto y a la vista de todo el mundo en repositorios públicos, por lo que si se usan las aplicaciones procedentes de fuentes oficiales no debería haber problema. Pero nada evita que puedan ser modificadas y recompiladas.

    Especificaciones técnicas #

    Con la ayuda de las especificaciones técnicas6 detalladas sobre el funcionamiento del EUDCC, del código fuente de las aplicaciones involucradas, y de otros muchos artículos, haremos un análisis exhaustivo del funcionamiento y de todos los pasos que se llevan a cabo a la hora de generar y leer un certificado COVID.

    El EUDCC se basa en una especificación concreta de certificados de salud digitales (HCERT)7.

    Generación del certificado #

    steps.png
    Procedimiento para la generación y la lectura de un código QR que contiene un certificado COVID

    Partimos de una estructura de datos JSON8, que define una serie de campos que pueden o deben ser rellenados con los datos procedentes de la base de datos de salud de la administración de turno. Hay campos obligatorios y otros opcionales (dependiendo del tipo de certificado).

    A la hora de generar el certificado, se cumplimentan estos datos y se obtiene un documento JSON, que es el payload, o carga, que es el que contiene la información estructurada, útil y legible por un humano o por una aplicación, y que será lo que se procese y muestre en pantalla al escanear.

    A continuación mostramos como ejemplo el payload9 que correspondería a una persona ficticia10 que ha recibido una dosis de una vacuna, pero no hay constancia de que haya sido testeada ni se haya recuperado de la enfermedad. Para mejor comprensión de cada campo se ha añadido un breve comentario a cada uno de ellos tras dos barras (//), pero hay que aclarar que estrictamente esto no es válido, ya que JSON no admite comentarios.

    {
      "1": "AT", // país emisor
      "4": 1624458597, // fecha de expiración en formato UNIX timestamp
      "6": 1624285797 // fecha de generación en formato UNIX timestamp
      "-260": {
        "1": {
          "dob": "1998-02-26", // fecha de nacimiento
          "nam": {
            "fn": "Musterfrau-Gößinger", // apellido(s)
            "fnt": "MUSTERFRAU<GOESSINGER", // apellido(s) normalizado(s)
            "gn": "Gabriele", // nombre
            "gnt": "GABRIELE" // nombre normalizado
          },
          "v": [
            {
              "ci": "URN:UVCI:01:AT:10807843F94AEE0EE5093FBC254BD813#B", // id único
              "co": "AT", // país de vacunación (Austria)
              "dn": 1, // dosis recibidas
              "dt": "2021-02-18", // fecha de vacunación
              "is": "Ministry of Health, Austria", // entidad emisora
              "ma": "ORG-100030215", // fabricante de la vacuna (Biontech)
              "mp": "EU/1/20/1528", // id de la vacuna (Biontech's Comirnaty)
              "sd": 2, // número total de dosis
              "tg": "840539006", // enfermedad (COVID-19)
              "vp": "1119349007" // tipo de vacuna (mRNA)
            }
          ],
          "ver": "1.2.1" // versión del formato
        }
      }
    }
    

    Hay una guía11 que detalla los elementos básicos del payload para que sea interoperable. En el anexo 1 se hace un listado de mínimos de los datos que son necesarios, y en el anexo 2 se explica cómo se puede construir y qué formatos puede tener el campo “ci” (Unique Vaccination Certificate/assertion Identifier, o UVCI).

    Este payload se codifica como CBOR12 13 (Concise Binary Object Representation), que es una representación binaria del JSON, que a su vez se cifra y firma digitalmente mediante un procedimiento llamado COSE14 (CBOR Object Signing and Encryption). De este modo se consigue que la integridad y autenticidad del payload sean verificables. El resultado se inserta en un CWT15 (CBOR Web Token). El payload va dentro de un campo “hcert” de esta estructura.

    El siguiente paso es la compresión mediante la librería zlib y su algoritmo DEFLATE16, que es una compresión sin pérdidas. Deflate implementa el algoritmo de Huffman17 que consiste en recodificar todos los símbolos del mensaje, de modo que se asignan códigos cortos a los símbolos utilizados con más frecuencia (los que aparecen más a menudo), mientras que los símbolos menos frecuentes reciben códigos binarios más largos.

    El resultado se codifica como base4518. Se trata de una propuesta para codificación de datos binarios muy reciente, y un poco más complicada que los habituales base16 (hexadecimal) y base64. Se escogió porque los 45 caracteres posibles forman parte de ASCII y son precisamente los que se pueden usar en un código QR.

    Podemos probar todo el proceso descrito anteriormente en una web19 que nos permite tanto codificar como decodificar nuestros payloads.

    Una vez obtenido el mensaje codificado, solo queda generar un código QR. Podemos aprender cómo se genera 20 21 paso a paso y utilizar cualquiera de los cientos de webs y aplicaciones que hacen todo el proceso por nosotros.

    Este procedimiento se puede implementar de múltiples formas. Podemos consultarlo en código Python22 de la forma más sencilla posible, o también en Java23.

    En esta web24 se pueden hacer pruebas de generación de EUDCC (EU HC1) con nuestros propios certificados, aunque obviamente no tendrán validez, ya que para eso los tendría que firmar una entidad certificadora de confianza con su clave privada, que es secreta y es donde descansa la confianza del sistema. Más adelante veremos más sobre esto.

    Lectura del certificado #

    A continuación vamos a utilizar algunas líneas de Python para decodificar el certificado paso a paso25 26. Utilizaremos algunos módulos de la librería estándar de Python y otros de terceros, concretamente base4527 y cbor228.

    python -m pip install base45 cbor2
    

    Partimos del contenido en bruto que hemos obtenido de la lectura de un código QR válido (el ejemplo muestra uno de una persona ficticia, obtenido del repositorio oficial29). Asignamos este contenido a la variable encoded.

    import base45
    
    encoded = "6BFOXN%TS3DH1QG9WA6H98BRPRHO DJS4/ R-%2% I+:9AVDQ81LO2-36/X0X6BMF6.UCOMIN6R%E5UX4795:/6N9R%EPXCROGO3HOWGOKEQBKL/645YPL$R-ROM47L*K1UPB65%PDMOL*9DJZI202K-JKYJGCC:H3J1D1I3-*TW C57DNGSE%C-3EXED2SSRST BD%USVJC1HCK0DM.C86U*XC0SSNST$JCD8CBZI+PB/VSQOL9DLSWCZ3EBKDVIJGDBDIT1NJGIA+OJ:CI-L3ZJA/3CZIJFVA.QO5VA81K0ECM8CXVDC8C 1JI7JSTNCA7G6M%28ODSINQIVQUIRYYQ4P7M9SB95S6M/355X7C25E8DLFEA3LS6FPOSXD79NT+X4VIOS0I63K*+7SLS9NTRFBOX4YGFD.O8RJ5XPUVPQRHIY1+ HNQ1PRAAUICO12Y99UE$V1*65PC8Q8J.Y37DT/Z7X.HB:I- 57HH1H1TRR9+VB-F4*2V4712IE2B:0WT/PUXR*2B$Y843C-NAKG6SWMC3VJ*F92215IY3SRZTM$0B61M10HOKU5"
    
    compressed = base45.b45decode(encoded)
    
    # compressed
    b"x\x9c\xbb\xd4\xe2\xbb\x88\xc5\x83#T\xc3J4\xd7\x8a\x8bQmA$\xa3\xdc\x12\x16\xa9\x94\xdcO\x15lR\tk\x14\x1f0&\x05\xf8X22/d\\\x92X\xd6\xb8*)%\x8f))71\xd7?\xc8]\xd7\xd0\xc0\xc0\xc0\xd8\xc0\xc8\xd04\xa9\xac \xdd\xcb\xc0\xdc)\xc2\xc08)\xa5$\xcb\x08(\xa6k`\xaakh\x91\x94\x9c\x0f\xd4\x9d\x94\x9cYa\x18\x1a\xe4g\x15\x1a\xe6\xecie`h\x15\xe0ce\xa8onil\xe2j\xealh\xe8\xe2\xe8bba\xeaf\xe9fd\xeedd\xe0\xe2h\xeahbh`a\x94\x94[\x90\xe3\x1a\xaao\xa8od\xa8ohjd\x99\x94Y\\\xe8\x9c\x9aWRT\x9a\xab\x90\xaa\x1b\x95R\x94_\x9e\x99\x98T\x9c\xc2\x94T\x92\x9eiab`jli``\x96\x9c\x97\x98\xbb$9-\xaf$?\xc8\xdf\xdd\xd1\xc7\xd3/\xd8\xdb\xd3\xc6;\xc8\xdf')-\xaf0(?=1'\xf3hKqv\xa6\xaew\xd1\xe1\xcd9\xc9\xe9y%\x99\xc1!\x8e~\x9e\xc1>\x8e\xe1I\xe9yY\xc1%\x89y\x99\xc5G\x9b\x12\xcb\x93\xcbR\x8bR\r\xf5\x8c\xf5\x0c\x92S\xf2\x93\xb2\x0c-M-t\r\r\x81(\xc2A}\x97\xcd\x1d\xdf\xe7\xb5=\xb1\x8d\xfc\x96).\n\x89}\n\xe7\xdao\xfcH}\xe7\x16\xb182\x8e\xbdWk\xfdL\xcdm\xdb~W\x84Eg_wSN2Z\xb3\xc2\xf5\xca}\x95\x105\x8fD\xde%\xeb\xa7\x06\x97\t\x02\x00C\xa2}\xff"
    

    Este es el resultado de la decodificación base45. Ahora lo descomprimimos.

    import zlib
    
    decompressed = zlib.decompress(compressed)
    
    # decompressed
    b"\xd2\x84M\xa2\x04H\x08U(:\x15m:\n\x01&\xa0Y\x01\x1e\xa4\x04\x1adm\xf2x\x06\x1a`\xac!\xe0\x01bPL9\x01\x03\xa1\x01\xa4av\x81\xaabdn\x02bmamORG-100030215bvpgJ07BX03bdtj2021-05-18bcobPLbcix1URN:UVCI:01:PL:1/7934E5C11DAD485F9F27B20DA5A41082bmplEU/1/21/1529bisqCentrum e-Zdrowiabsd\x02btgi840539006cnam\xa4cfntoROGALINSKI<KROLbfnqRogali\xc5\x84ski-Kr\xc3\xb3lcgntiSTANISLAWbgnjStanis\xc5\x82awcvere1.3.0cdobj1958-11-11X@'\xba<\xdcM\xe7}\x8c]\x81\x0f9dD a\x8e \xce\x87\xd8\xf8e\xeeFX\xa3Y^\x07\x8d*\xaf\x99)\xb6\xb6\xfbxV[k\xd7F#b2\xac\xa8E\xd4\xdf$T&Ha\r\xa4\xaf\x95Sv\x11"
    

    Aquí ya podemos leer algunas cosas con sentido. El siguiente paso es decodificar con CBOR.

    import cbor2
    
    cbor_decoded = cbor2.loads(decompressed)
    
    # cbor_decoded
    CBORTag(18, [b'\xa2\x04H\x08U(:\x15m:\n\x01&', {}, b'\xa4\x04\x1adm\xf2x\x06\x1a`\xac!\xe0\x01bPL9\x01\x03\xa1\x01\xa4av\x81\xaabdn\x02bmamORG-100030215bvpgJ07BX03bdtj2021-05-18bcobPLbcix1URN:UVCI:01:PL:1/7934E5C11DAD485F9F27B20DA5A41082bmplEU/1/21/1529bisqCentrum e-Zdrowiabsd\x02btgi840539006cnam\xa4cfntoROGALINSKI<KROLbfnqRogali\xc5\x84ski-Kr\xc3\xb3lcgntiSTANISLAWbgnjStanis\xc5\x82awcvere1.3.0cdobj1958-11-11', b"'\xba<\xdcM\xe7}\x8c]\x81\x0f9dD a\x8e \xce\x87\xd8\xf8e\xeeFX\xa3Y^\x07\x8d*\xaf\x99)\xb6\xb6\xfbxV[k\xd7F#b2\xac\xa8E\xd4\xdf$T&Ha\r\xa4\xaf\x95Sv\x11"])
    

    El contenido de cbor_decoded es un objeto que contiene varias propiedades. La etiqueta 18 indica que estamos ante un elemento de tipo COSE_Sign1 (COSE Single Signer Data Object). Extraemos el contenido del objeto:

    cbor_decoded_content = cbor_decoded.value
    
    # cbor_decoded_content
    [b'\xa2\x04H\x08U(:\x15m:\n\x01&',
     {},
     b'\xa4\x04\x1adm\xf2x\x06\x1a`\xac!\xe0\x01bPL9\x01\x03\xa1\x01\xa4av\x81\xaabdn\x02bmamORG-100030215bvpgJ07BX03bdtj2021-05-18bcobPLbcix1URN:UVCI:01:PL:1/7934E5C11DAD485F9F27B20DA5A41082bmplEU/1/21/1529bisqCentrum e-Zdrowiabsd\x02btgi840539006cnam\xa4cfntoROGALINSKI<KROLbfnqRogali\xc5\x84ski-Kr\xc3\xb3lcgntiSTANISLAWbgnjStanis\xc5\x82awcvere1.3.0cdobj1958-11-11',
     b"'\xba<\xdcM\xe7}\x8c]\x81\x0f9dD a\x8e \xce\x87\xd8\xf8e\xeeFX\xa3Y^\x07\x8d*\xaf\x99)\xb6\xb6\xfbxV[k\xd7F#b2\xac\xa8E\xd4\xdf$T&Ha\r\xa4\xaf\x95Sv\x11"]
    

    El contenido consiste en una lista con cuatro elementos: la cabecera, un campo vacío, el payload y la firma. Los extraemos a sus respectivas variables.

    (cbor_header, _, cbor_payload, signature) = cbor_decoded_content
    

    Partiendo del cbor_payload obtenemos de nuevo con cbor2 el JSON original.

    payload = cbor2.loads(cbor_payload)
    
    # payload
    {
      4: 1684927096,
      6: 1621893600,
      1: 'PL',
      -260: {
        1: {
          'v': [{
            'dn': 2,
            'ma': 'ORG-100030215',
            'vp': 'J07BX03',
            'dt': '2021-05-18',
            'co': 'PL',
            'ci': 'URN:UVCI:01:PL:1/7934E5C11DAD485F9F27B20DA5A41082',
            'mp': 'EU/1/21/1529',
            'is': 'Centrum e-Zdrowia',
            'sd': 2,
            'tg': '840539006'
          }],
          'nam': {
            'fnt': 'ROGALINSKI<KROL',
            'fn': 'Rogaliński-Król',
            'gnt': 'STANISLAW',
            'gn': 'Stanisław'
          },
          'ver': '1.3.0',
          'dob': '1958-11-11'
        }
      }
    }
    

    Ahora vamos a buscar el certificado con el que se firmó. Para ello extraemos también el header:

    header = cbor2.loads(cbor_header)
    
    # header
    {4: b'\x08U(:\x15m:\n', 1: -7}
    

    Nos devuelve un diccionario con dos elementos, cuyas claves son 4 y 1. El valor -7 del campo 1 indica los algoritmos criptográficos usados (en este caso ECDSA con SHA-256), y el valor del campo 4 es un binario que tendremos que codificar en base64:

    kid = base64.b64encode(header[4])
    
    # kid
    b'CFUoOhVtOgo='
    

    Este parámetro se conoce como kid30 (key id) e indica con qué clave pública ha sido firmado el certificado. Hacemos una búsqueda en la lista de entidades certificadoras confiables31, y comprobamos que efectivamente corresponde a una entidad certificadora polaca, lo cual concuerda con lo que dice el contenido del payload.

    También es posible realizar este procedimiento32 con una herramienta web llamada CyberChef33, con la que podemos ir realizando todo el proceso visualmente con bloques y que también puede descargarse y ser ejecutada offine.

    La verificación de la validez del certificado no vamos a tratarla aquí por su complejidad, pero puede consultarse en varios sitios34 35 36.

    Sistemas criptográficos y firma digital #

    Un sistema criptográfico de clave asimétrica37 es aquel donde se generan dos claves, una pública y otra privada, donde una deriva de la otra, y que tienen la particularidad de que lo que se cifra con una de ellas, se descifra única y exclusivamente con la otra. Existen dos principales familias de algoritmos para generar estas claves: RSA38 y EC39 (curva elíptica).

    Un certificado digital40 es un archivo que contiene información sobre una persona o entidad y su clave pública, de modo que podemos asociar ambas cosas. Para que esta relación no pueda ser disociada, se firma digitalmente a su vez con la clave pública de otra persona o entidad, que es la que lo ratifica. Esta firma hace que se pueda detectar cualquier variación de la integridad de estos datos.

    En el caso del EUDCC, para comprobar la autenticidad e integridad, se usa una firma digital. Hay algunas variantes en cuanto a funcionamiento y algoritmos, pero lo más habitual es que la firma digital se genere de este modo: primero se calcula el hash del documento, y posteriormente se cifra este hash con la clave privada de una entidad certificadora de confianza. La clave pública de esta entidad será pública y accesible en su certificado, con lo cual, si somos capaces de descifrar con esta clave pública, y el hash resultante coincide con el del documento, estaremos en condiciones de asegurar tanto su integridad como su autenticidad.

    Una infraestructura de clave pública41 (Public Key Infrastructure, PKI) es un sistema que permite generar, administrar, utilizar o revocar una serie de certificados digitales. La más común es X.50942, que especifica un formato estándar para certificado de clave pública y un algoritmo de validación. Este formato es el que se usará para validar los EUDCC, y es el mismo que se utiliza en la web cuando usamos HTTPS, para asegurar tanto la integridad como la autenticidad de los datos emitidos.

    El funcionamiento del PKI es el siguiente: existen una serie de autoridades certificadoras de confianza (Root CA), que están autorizadas para emitir lo que se conoce como un certificado raíz, que se firma a sí mismo, y que puede firmar a otras autoridades subordinadas (CA). Estas, a su vez, pueden firmar a otras instituciones, y así sucesivamente. Evidentemente, la seguridad de este sistema radica en última instancia en que la clave privada de la autoridad certificadora no salga nunca a la luz.

    En el caso de España, por ejemplo, es la European Agency of Digital Trust43 (EADTrust) quien firma digitalmente los certificados que a su vez emiten los diferentes servicios sanitarios de las comunidades autónomas.

    Por ejemplo, si abrimos el certificado con el que firma los EUDCC de los vacunados en Castilla y León, nos encontramos esto:

    Identidad: GERENCIA REGIONAL DE SALUD CASTILLA Y LEÓN (SACYL)
    Verificado por: EADTrust ECC 256 SubCA For Qualified Certificates 2019
    

    Ahora vamos a la web de la EAD Trust y buscamos el certificado con que se firmó:

    Identidad: EADTrust ECC 256 SubCA For Qualified Certificates 2019
    Verificado por: EADTrust ECC 256 Root CA For Qualified Certificates 2019
    

    Y por último, en esa misma web, podemos encontrar el certificado raíz, que se firma a sí mismo, y es por tanto en el que depositamos la confianza en última instancia:

    Identidad: EADTrust ECC 256 Root CA For Qualified Certificates 2019
    Verificado por: EADTrust ECC 256 Root CA For Qualified Certificates 2019
    

    Podemos encontrar estos certificados con mayor o menor dificultad en internet, aunque todos deben ser públicos para que pueda comprobarse la integridad y autenticidad de los documentos que firman. Por ejemplo, el gobierno suizo publica 44 su CA raíz y las tres subordinadas.

    Para aprender más sobre criptografía básica y firmas digitales, recomendamos leer el libro gratuito y de acceso libre de Svetlin Nakov45.

    Aplicaciones móviles #

    Aunque se han desarrollado múltiples aplicaciones móviles para gestionar los EUDCC, vamos a destacar los desarrollos de dos países, Suiza46 y Alemania, ya que ambos son de código abierto y además han sido publicados en el repositorio de aplicaciones libres F-Droid, siendo así un buen ejemplo de transparencia.

    Ambas funcionan igual, en esencia, y tienen interfaces similares. Por un lado tenemos la aplicación para portar nuestro EUDCC, con la que haremos una foto al QR que tenemos. La aplicación extraerá los datos, comprobará su validez y replicará el QR, de modo que podremos mostrarlo fácilmente para ser leído por la otra aplicación.

    La otra aplicación, la que efectúa la comprobación, está pensada para los gestores de establecimientos o eventos a los que se requiere controlar que sus clientes o asistentes estén en posesión de un EUDCC válido. Estas aplicaciones implementan el flujo antes descrito, y además se descargan periódicamente la información actualizada que contiene las claves públicas de las entidades verificadoras, para poder efectuar la validación offline.

    Gracias a que el sistema está estandarizado, y que todas las aplicaciones acceden a un repositorio común donde se encuentran todas las claves públicas de todas las entidades emisoras autorizadas, en principio podemos usar indistintamente todas estas aplicaciones, y usar las de cualquier país tanto para mostrar como para leer EUDCCs, así como desarrollos de terceros.

    Referencias #


    1. Pandemia de COVID-19. https://es.wikipedia.org/wiki/Pandemia_de_COVID-19 ↩︎

    2. EU Digital COVID Certificate – Understanding the Global COVID Certificate Landscape (en inglés). https://www.lfph.io/2021/10/12/eu-digital-covid-certificate/ ↩︎

    3. Certificado COVID digital de la UE. https://ec.europa.eu/info/live-work-travel-eu/coronavirus-response/safe-covid-19-vaccines-europeans/eu-digital-covid-certificate_es ↩︎

    4. Interim guidance for developing a Smart Vaccination Certificate (en inglés) https://www.who.int/publications/m/item/interim-guidance-for-developing-a-smart-vaccination-certificate ↩︎

    5. QR Code (en inglés). https://en.wikipedia.org/wiki/QR_code ↩︎

    6. Sanidad electrónica y COVID-19. https://ec.europa.eu/health/ehealth/covid-19_es ↩︎

    7. Electronic Health Certificates (en inglés). https://github.com/ehn-dcc-development/hcert-spec ↩︎

    8. JSON. https://es.wikipedia.org/wiki/JSON ↩︎

    9. eHealth Network. Guidelines on Technical Specifications for EU Digital COVID Certificates. JSON Schema Specification (en inglés). https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf ↩︎

    10. What’s Inside the EU Green Pass QR Code?. https://gir.st/blog/greenpass.html ↩︎

    11. eHealth Network. Guidelines on Verifiable Vaccination Certificates. Basic Interoperability Elements (en inglés). https://ec.europa.eu/health/sites/default/files/ehealth/docs/vaccination-proof_interoperability-guidelines_en.pdf ↩︎

    12. RFC 8949 Concise Binary Object Representation (CBOR) (en inglés). https://cbor.io ↩︎

    13. CBOR playground (en inglés). https://cbor.me ↩︎

    14. CBOR Object Signing and Encryption (COSE) (en inglés). https://cose-wg.github.io/cose-spec ↩︎

    15. CBOR Web Token (CWT) (en inglés). https://tools.ietf.org/id/draft-ietf-ace-cbor-web-token-15.html ↩︎

    16. Algoritmo Deflación. https://es.wikipedia.org/wiki/Deflaci%C3%B3n_(algoritmo) ↩︎

    17. Algoritmo de Huffman. https://es.wikipedia.org/wiki/Algoritmo_de_Huffman https://es.wikipedia.org/wiki/Codificaci%C3%B3n_Huffman ↩︎

    18. The Base45 Data Encoding (en inglés). https://datatracker.ietf.org/doc/draft-faltstrom-base45 ↩︎

    19. DenCode base45 (en inglés). https://dencode.com/string/base45 ↩︎

    20. Creating a QR code step by step (en inglés). https://www.nayuki.io/page/creating-a-qr-code-step-by-step ↩︎

    21. QR Code Tutorial (en inglés). https://www.thonky.com/qr-code-tutorial ↩︎

    22. Trivial/rudimentary eHN-simplified implementation (en inglés). https://github.com/ehn-dcc-development/ehn-sign-verify-python-trivial ↩︎

    23. Let’s make a COVID Certificate (ENCODING) (en inglés). https://dx.dragan.ba/covid-certificate-encoding ↩︎

    24. Digital Covid Certificate Generator (en inglés). https://vitorpamplona.com/vaccine-certificate-qrcode-generator/eu.dgc.html ↩︎

    25. Decoding the EU Digital Covid Certificate QR code (en inglés). https://www.bartwolff.com/Blog/2021/08/08/decoding-the-eu-digital-covid-certificate-qr-code ↩︎

    26. Finnish National Vaccination Certificate. Verification process and technical specification (en inglés). https://www.kanta.fi/documents/20143/1474889/finnish-national-vaccination-certificate-verification.pdf ↩︎

    27. Librería base45 en PyPi (en inglés). https://pypi.org/project/base45 ↩︎

    28. Documentación de la librería cbor2 (en inglés). https://cbor2.readthedocs.io/en/latest/index.html ↩︎

    29. Official GitHub Organization of the EU Digital COVID Certificates (EUDCC) project (en inglés). https://github.com/eu-digital-green-certificates/dgc-testdata ↩︎

    30. EU DCC signing certificates. https://github.com/kwaidas/Certificate/blob/main/docs/certificates.md ↩︎

    31. SE Digital Covid Certificate Trust Point (en inglés). https://qa.dgc.idsec.se/tp/ ↩︎

    32. ¿Qué contienen los códigos QR en el Certificado Covid de la UE y cómo comprobarlo? (en polaco). https://informatykzakladowy.pl/co-zawieraja-qr-kody-w-unijnym-certyfikacie-covid-i-jak-to-sprawdzic/ ↩︎

    33. CyberChef (en inglés). https://cyberchef.org/ ↩︎

    34. Verifying EU Digital COVID-19 Certificate with Python CWT (en inglés). https://medium.com/@dajiaji/verifying-eu-digital-covid-19-certificate-with-python-cwt-fd3d5de27eed ↩︎

    35. Mario’s Blog, Verificare un Green Pass. https://mariopiccinelli.it/blog/verificare-un-green-pass ↩︎

    36. DCC Green Pass Decoder. Signature Validation. https://github.com/floysh/DCC-green-pass-decoder/blob/main/docs/signature-validation.md ↩︎

    37. Criptografía asimétrica. https://es.wikipedia.org/wiki/Criptografia_asimetrica ↩︎

    38. How RSA Works. https://www.youtube.com/watch?v=rVQpK6NcYIE ↩︎

    39. Elliptic Curve Cryptography Overview. https://www.youtube.com/watch?v=dCvB-mhkT0w ↩︎

    40. Certificado digital. https://es.wikipedia.org/wiki/Certificado_digital ↩︎

    41. Infraestructura de clave pública. https://es.wikipedia.org/wiki/Infraestructura_de_clave_publica ↩︎

    42. X.509. https://es.wikipedia.org/wiki/X.509 ↩︎

    43. Documentos vigentes de la EADTrust. https://eadtrust.eu/documentos-vigentes/ ↩︎

    44. Swiss Government Root CA I (en alemán) https://www.bit.admin.ch/bit/de/home/subsites/allgemeines-zur-swiss-government-pki/rootzertifikate/swiss-government-root-ca-i.html ↩︎

    45. Svetlin Nakov: Practical Cryptography for Developers (en inglés). https://cryptobook.nakov.com ↩︎

    46. Swiss Covid Certificate - Documents (en inglés). https://github.com/admin-ch/CovidCertificate-Documents ↩︎