Creación y Verificación de un Certificado Covid.

En primer lugar, se requiere ordenar los datos relativos al certificado (nombre, edad, fecha vacunación, etc.) en un formato entendible para los sistemas informáticos.

El formato JSON es un formato similar al XML, pero por lo general es más corto y más fácil de analizar.

XML es un lenguaje de marcado similar a HTM, pero menos cómodo por la cantidad y longitud de datos.

La estructura común se describe a continuación:

«JSON»: {

«ver»: <version information>,

«nam»: {

<person name information>

},

«dob»: <date of birth>,

«v» or «t» or «r»: [

{<vaccination dose or test or recovery information, one entry>}

]

}

Una vez definida la estructura se genera el archivo JSON con los daos del portador del certificado:

{«6″:1639725847,»4″:1684671300,»1″:»ES»,»-260″:{«1»:{«ver»:»1.3.0″,»nam»:{«fn»:»CORDON VERA»,»gn»:»FRANCISCO AN»,»fnt»:»CORDON<VERA»,»gnt»:»FRANCISCO<AN»},»dob»:»19xx-01-14″,»v»:[{«tg»:»840539006″,»vp»:»1119349007″,»mp»:»EU/1/20/1507″,»ma»:»ORG-100031184″,»dn»:2,»sd»:2,»dt»:»2021-12-15″,»co»:»ES»,»is»:»Servicio Andaluz de Salud»,»ci»:»01ES01V5201A44C5F0A11ECXXXX#3″}]}}}

Estos serian mis datos con algunas alteraciones por seguridad.

El paso siguiente seria convertirlo a CBOR.

CBOR es una alternativa a JSON para serializar datos con menos bytes y con menos esfuerzo informático. Menos bytes significa más velocidad de solicitud y respuesta y menos uso de memoria. Para datos pequeños, no es visible, pero si guardamos algunos bytes para millones de solicitudes por segundo, lo hará.

Conversión de mi certificado en CBOR:

Para ello he utilizado un algoritmo en Python, de mi propia creación (existen multitudes en la nube).

¤a6a¼;a4dj
Da1bESd-260¡a1¤cvere1.3.0cnam¤bfnkCORDON VERAbgnlFRANCISCO ANcfntkCORDON<VERAcgntlFRANCISCO<ANcdobj1967-01-14avªbtgi840539006bvpj1119349007bmplEU/1/20/1507bmamORG-100031184bdn[1]bsd[1]bdtj2021-12-15bcobESbisxServicio Andaluz de Saludbcix‑01ES01V520XX44C5F0A11EC99400#3

Ahora la empresa certificadora del documento, en mi caso el Servicio Andaluz de salud, firma este archivo con su clave privada y secreta, cifrando el certificado.

Posteriormente y para reducir los datos lo comprimimos con el formato JLIB (muy similar al conocido ZIP)

El último paso sería volver a codificar los datos, en esta ocasión en Base-45, un estándar de codificación propuesto para codificar datos con 45 caracteres, por ser la codificación compacta más adecuada para códigos QR.

El resultado sería:

HC1:NCFOXN%TSMAHN-HL S*F19I0V-G -D-AH-UC1ROT$SD P++IAEFF%GDJ5BYEOTAF/8X*G3M9JUPY0BZW4V/AY73CNN1M3I6H3H31H3CB75J7BG7LOJW77/AJM83NJJIC5SP499TP+MX/KS96/-KKTCY73JC3MD34LT.LJ3ZC58J0ATC%CB+2W/SS KKJ5XP40P0X5TFV4R/S09T./0LWTKD3323/I0SRJB/S7-SN2H N37J3JFTULJ5CB8X2.36D-I/2DBAJDAJCNB-43 X4VV2 73-E3GG3V20-7TZD5CC9T0HB/CCNNT*8JZII7JSTNB95726KZ5QNQ8ORQFA92SD9R%E53X7$ 74/QT+Q5.OCA7T5MN%4IK04T9P8QHIG02J$%25I3KC3X83F67*WUY6KU2VOAF:MDX-GSBWPJNFVVINFEXGT5S-H5ZWP4 4M 18GT:HE9JJS1IXWJP8R25AZT74ZS5BQQY6N-6F5N/9JDM3A5H4SNYM0T2L. E

Y con esto tendríamos el QR del certificado terminado.

Certificados fraudulentos

Miles de certificados COVID-19 falsos descubiertos en Suiza - SWI  swissinfo.ch

Miles de certificados COVID-19 falsos descubiertos en Suiza.

Últimamente están saliendo noticias de falsificaciones de estos certificados, la única forma de realizar uno que engañe a la aplicación que los verifica, seria conociendo la firma o clave privada de alguna de las entidades certificadoras. Por desgracia ya se han filtrado algunas en internet:

kid: 53FxxjX/4aJs=
key: <EllipticCurvePublicNumbers(curve=secp256r1, x=592244247113166610848779733018418xx584140021680113528472675651838972371380627, y=54841068689176540860306147861xx76004028606373898471432794562118907413910993957>

kid: HhkeqxxrtQ0U=
key: <EllipticCurvePublicNumbers(curve=secp256r1, x=58474994431552591028397454866551xx597403245555156280299836700796569353760692, y=9416038953242826359976521318443154xx48511972729790083405292977908540518398962>

He modificado algunos caracteres por razones obvias.

Aumenta la ESTAFA de venta de certificados de VACUNACIÓN Covid FALSOS I  RTVE Noticias - YouTube

Certificado de mickeymouse

VR 0: C=FR,ID=URN:UVCI:01:FR:W7V2BE46QSBJ#L,ISS=CNAM

KID: 53FOjX/4aJs=

Issued At: 2021-10-27 11:20:48 UTC

Signed By: CN=DSC_FR_023,OU=180035024,O=CNAM,C=FR (issued by: CN=CSCA-FRANCE,O=Gouv,C=FR)

Expiration: 2023-10-13 22:00:00 UTC

Personal Name: MICKEY MOUSE

DOB: 2001-12-31

Estas claves privadas ya han sido revocadas y no es posible falsificar certificados con ellas, siempre y cuando esten actualizadas las App de verificación.

Validación del certificado

El proceso de descodificación del certificado QR se obtiene realizando todos los pasos en el sentido inverso, pero con la salvedad que el descifrado se realiza con la clave pública la cual es conocida y facilitada por la entidad certificadora.

La aplicación para comprobar si es correcto y cumple los requisitos no necesita conexión a internet, aunque si es conveniente actualizaciones diarias para obtener los certificados revocados, añadir nuevas claves publicas de nuevos organismos y conocer los criterios de valoración para dar el color verde (tener la pauta completa, tiempo pasado desde la última vacuna, etc.) ya que varían según el país emisor.

En este ejemplo mediante una App de mi creación, puedo validar fácilmente los certificados:

Esta aplicación permite la verificación de cualquier certificado Covid Digital emitido por un país de la UE. Esta app funciona escaneando el código QR de los certificados covid emitidos por la UE, verificando su autenticidad.

Parte de código utilizado en mi APP:

Sub GreenPassParse( s As String ) As String

            Dim partialparse As StringBuilder

            partialparse.Initialize

            json.Initialize( s )

            Dim walker As Map = json.NextObject

            Dim country As String = walker.Get(«1»)

            Dim rec260 As Map = walker.Get(«-260»)

            Dim rec1 As Map = rec260.Get(«1»)

            Dim name As Map = rec1.Get(«nam»)

            partialparse.Append( «Certificado emitido en: » & country & »  Apellidos y nombre: » & name.Get(«fn») & «, » & name.Get(«gn») & » Fecha de nacimiento: » & rec1.Get(«dob»)).Append(CRLF)

    Dim vacclist As List

            vacclist.Initialize

            Dim testlist As List

            testlist.Initialize

            Dim recoverylist As List

            recoverylist.Initialize

            Try

                        vacclist = rec1.Get(«v»)  ‘ vaccination

                        If vacclist.IsInitialized Then

                        For Each rec As Map In vacclist

                                    Dim a As Int = rec.Get(«tg»)

                                    Dim against As String

                                    If a = 840539006 Then

                                               against = «Covid»

                                    Else

                                               against = «unknown target»

                                    End If

                                    Dim d As Int = rec.Get(«dn»)

                                               partialparse.Append( «Fecha de vacunación: » & rec.Get(«dt») & » Emisor del certificado: » & rec.Get(«is») & » Número de dosis: » & d & » Enfermedad que se previene: » & against& » Identificador del certificado: » & rec.Get(«ci»)).Append(CRLF)

                        Next

                        End If

            Catch

                        Log(LastException)

            End Try

            Try

                        testlist = rec1.Get(«t»)

                        If testlist.IsInitialized Then

                                    For Each rec As Map In testlist

                                               Dim a As Int = rec.Get(«tg»)

                                               Dim against As String

                                               If a = 840539006 Then

                                                           against = «Covid»

                                               Else

                                                           against = «unknown target»

                                               End If

                                               Dim r As Int = rec.Get(«tr»)

                                               Dim testresult As String

                                               If r = 260415000 Then

                                                           testresult = «undetected»

                                               Else if r = 260373001 Then

                                                           testresult = «detected…»

                                               Else

                                                           testresult = «unknown»

                                               End If

                                               partialparse.Append( «date of test: » & rec.Get(«sc») & » where: » & rec.Get(«co») & » against: » & against & » result: » & testresult).Append(CRLF)

                                    Next

                        End If

            Catch

                        Log(LastException)

            End Try

            Try

                        recoverylist = rec1.Get(«r»)

                        If recoverylist.IsInitialized Then

                        For Each rec As Map In recoverylist

                                    Dim a As Int = rec.Get(«tg»)

                                    Dim rfrom As String

                                    If a = 840539006 Then

                                               rfrom = «Covid»

                                    Else

                                               rfrom = «unknown target»

                                    End If

                                    partialparse.Append( «recovery from: » & rfrom & » valid until: » & rec.Get(«du»)).Append(CRLF)

                        Next

                        End If

            Catch

                        Log(LastException)

            End Try

            Return(partialparse.ToString )

End Sub

Sub SanipassParse( s As String ) As String

            Dim matcher As Matcher

            matcher = Regex.Matcher(«DC\d\d», s)

            If matcher.Find Then

                        Dim pattern As String = matcher.Group(0)

            End If

            Dim startpos As Int = s.IndexOf( pattern )

            If startpos > 0 Then

                        s = s.SubString( startpos )

            End If

            ‘ DC01 DC02 DC03 DC04 all exist and with different

            ‘ formats

            Dim masterregex As String

            Dim personaldata As Int

            If pattern.CompareTo(«DC04») = 0 Then

                        masterregex = «(.{2,2})(.{2,2})(.{4,4})(.{4,4})(.{4,4})(.{4,4})(.{2,2})(.{2,2})(.{2,2})(.*)»

                        ‘ find all the various «groups» in the string

                        personaldata = 10

            else If pattern.CompareTo(«DC03») = 0 Then

                        masterregex = «(.{2,2})(.{2,2})(.{4,4})(.{4,4})(.{4,4})(.{4,4})(.{2,2})(.{2,2})(.*)»

                        ‘ group(7) type of cert

                        personaldata = 9

            else If pattern.CompareTo(«DC02») = 0 Or pattern.CompareTo(«DC01») Then

                        masterregex = «(.{2,2})(.{2,2})(.{4,4})(.{4,4})(.{4,4})(.{4,4})(.{2,2})(.*)»

                        ‘ group(7) type of cert

                        personaldata = 8

            Else

                        Log(«unknown version: » & pattern)

            End If

            If masterregex.Length > 0 Then   ‘ we have a matching pattern

                        matcher = Regex.Matcher( masterregex, s )

                        If matcher.find Then

                                    Dim certtype As String = matcher.Group(7)

                                    If certtype = «B2» Then

                                               certtype = «test»

                                    else if certtype = «L1» Then

                                               certtype = «vaccination»

                                    Else

                                               certtype = «unknown type of certificate»

                                    End If

                                    Dim importantstuff = matcher.Group( personaldata )   ‘ will vary depending on version

                                    Dim personregex = «F0(.*?)%1DF1(.*?)%1DF2(.{8,8})F3(.)F4(.*?)%1DF5(.)F6(.*?)%1F»       ‘ ends with %1F  the rest is signature

                                    Dim personmatcher As Matcher

                                    personmatcher = Regex.Matcher(personregex, importantstuff)

                                    If personmatcher.Find Then

                                               Dim dob As String = personmatcher.Group(3)

                                               dob = dob.SubString2(0,2) & «-» & dob.SubString2(2,4) & «-» & dob.SubString2(4,8)

                                               Log(certtype & » for: » & personmatcher.Group(1) & «, » & personmatcher.Group(2) & » » & dob & » » & personmatcher.group(4) & » «)

                                    End If

                        End If

            End If

End Sub

Se verifican tres aspectos:

  1. Que el certificado esta firmado electrónicamente por uno de los emisores permitidos.
  2. Que el certificado no esta revocado.
  3. Que el certificado cumple con los criterios establecidos de validez en España.

Si alguno de estos tres aspectos no se cumplen, el certificado se considera inválido.

– Puede funcionar sin necesidad de acceso a Internet.

– No almacena ninguna información del certificado verificado, ni realiza ninguna comunicación al respecto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *