File indexing completed on 2024-05-19 05:17:26

0001 /*
0002  * SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003  * SPDX-License-Identifier: LGPL-2.0-or-later
0004  */
0005 
0006 #include "../src/lib/nl-coronacheck/nlbase45.cpp"
0007 #include "../src/lib/openssl/opensslpp_p.h"
0008 
0009 #include <QDebug>
0010 #include <QFile>
0011 
0012 // creative string encoding...
0013 static QByteArray decodeByteArray(const uint8_t *&it, std::size_t length)
0014 {
0015     auto ai = openssl::asn1_integer_ptr(d2i_ASN1_INTEGER(nullptr, &it, length));
0016 
0017     auto bn = openssl::bn_ptr(BN_new());
0018     BN_zero(bn.get());
0019     for (auto i = 0; i < ai->length; ++i) {
0020         BN_mul_word(bn.get(), 1 << 8);
0021         BN_add_word(bn.get(), ai->data[i]);
0022     }
0023     BN_div_word(bn.get(), 2);
0024 
0025     QByteArray s;
0026     s.resize(BN_num_bytes(bn.get()));
0027     BN_bn2bin(bn.get(), reinterpret_cast<uint8_t*>(s.data()));
0028 
0029     return s;
0030 }
0031 
0032 static void dumpMetaData(const QByteArray &md)
0033 {
0034     long int length = 0;
0035     int tag = 0, asn1Class = 0;
0036     auto it = reinterpret_cast<const uint8_t*>(md.constData());
0037     const auto endIt = it + md.size();
0038     ASN1_get_object(&it, &length, &tag, &asn1Class, md.size());
0039 //     qDebug() << length << tag << asn1Class << ASN1_tag2str(tag);
0040 
0041     while (it != endIt) {
0042         auto it2 = it;
0043         ASN1_get_object(&it, &length, &tag, &asn1Class, std::distance(it, endIt));
0044         if (tag == V_ASN1_EOC && asn1Class == 0x0) {
0045             break;
0046         }
0047 //         qDebug() << length << tag << asn1Class << ASN1_tag2str(tag);
0048         if (tag == V_ASN1_OCTET_STRING) {
0049             auto os = openssl::asn1_octet_string_ptr(d2i_ASN1_OCTET_STRING(nullptr, &it2, length + std::distance(it2, it)));
0050             qDebug() << "version:" << QByteArray((const char*)os->data, os->length);
0051             it = it2;
0052         } else if (tag == V_ASN1_PRINTABLESTRING) {
0053             auto ps = openssl::asn1_printable_string_ptr(d2i_ASN1_PRINTABLESTRING(nullptr, &it2, length + std::distance(it2, it)));
0054             qDebug() << "issuer key:" << QByteArray((const char*)ps->data, ps->length);
0055             it = it2;
0056         } else {
0057             it += length;
0058         }
0059     }
0060 }
0061 
0062 static const char *field_names[] = {
0063     "isSpecimen",
0064     "isPaperProof",
0065     "validFrom",
0066     "validForHours",
0067     "firstNameInitial",
0068     "lastNameInitial",
0069     "birthDay",
0070     "birthMonth"
0071 };
0072 
0073 static void dumpInnerSequence(const uint8_t *&it, const uint8_t *endIt)
0074 {
0075     long int length = 0;
0076     int tag = 0, asn1Class = 0;
0077 
0078     // metadata field
0079     auto it2 = it;
0080     ASN1_get_object(&it, &length, &tag, &asn1Class, std::distance(it, endIt));
0081     dumpMetaData(decodeByteArray(it2, length + std::distance(it2, it)));
0082     it = it2;
0083 
0084     // string fields
0085     int i = 0;
0086     while (it != endIt) {
0087         it2 = it;
0088         ASN1_get_object(&it, &length, &tag, &asn1Class, std::distance(it, endIt));
0089         if (tag == V_ASN1_EOC && asn1Class == 0x0) {
0090             break;
0091         }
0092 //         qDebug() << length << tag << asn1Class << ASN1_tag2str(tag);
0093         qDebug() << field_names[i++] << decodeByteArray(it2, length + std::distance(it2, it));
0094         it = it2;
0095     }
0096 }
0097 
0098 static void dumpOuterSequence(const uint8_t *&it, const uint8_t *endIt)
0099 {
0100     long int length = 0;
0101     int tag = 0, asn1Class = 0;
0102     while (it != endIt) {
0103         ASN1_get_object(&it, &length, &tag, &asn1Class, std::distance(it, endIt));
0104         if (tag == V_ASN1_EOC && asn1Class == 0x0) {
0105             break;
0106         }
0107         qDebug() << length << tag << asn1Class << ASN1_tag2str(tag);
0108         if (tag == V_ASN1_SEQUENCE) {
0109             dumpInnerSequence(it, it + length);
0110         } else {
0111             // TODO these fields have to be the signature
0112             it += length;
0113         }
0114     }
0115 }
0116 
0117 int main(int argc, char **argv)
0118 {
0119     QFile f;
0120     f.open(stdin, QFile::ReadOnly);
0121     const auto in = f.readAll();
0122 
0123     // strip prefix
0124     if (!in.startsWith("NL2:")) {
0125         return 1;
0126     }
0127 
0128     // "base45" decode
0129     const auto base45Decoded = NLBase45::decode(in.begin() + 4, in.end());
0130 //     qDebug() << base45Decoded;
0131 
0132     long int length = 0;
0133     int tag = 0, asn1Class = 0;
0134     auto it = reinterpret_cast<const uint8_t*>(base45Decoded.constData());
0135     ASN1_get_object(&it, &length, &tag, &asn1Class, base45Decoded.size());
0136     qDebug() << length << tag << asn1Class << ASN1_tag2str(tag);
0137     dumpOuterSequence(it, it + length);
0138 
0139     return 0;
0140 }