6#include "nlcoronacheckparser_p.h"
9#include "irmapublickey_p.h"
10#include "irmaverifier_p.h"
12#include "openssl/asn1_p.h"
13#include "openssl/bignum_p.h"
15#include <KTestCertificate>
16#include <KVaccinationCertificate>
18#include <QCryptographicHash>
22void NLCoronaCheckParser::init()
24 Q_INIT_RESOURCE(nl_public_keys);
27static QByteArray nlDecodeAsn1ByteArray(
const ASN1::Object &obj)
29 auto it = obj.
begin();
30 auto ai = openssl::asn1_integer_ptr(d2i_ASN1_INTEGER(
nullptr, &it, obj.size()));
32 qWarning() <<
"invalid ASN.1 structure";
35 auto bn = openssl::bn_ptr(BN_new());
37 for (
auto i = 0; i < ai->length; ++i) {
38 BN_mul_word(bn.get(), 1 << 8);
39 BN_add_word(bn.get(), ai->data[i]);
41 BN_div_word(bn.get(), 2);
42 return Bignum::toByteArray(bn);
50 const auto rawData = NLBase45::decode(data.
begin() + 4, data.
end());
52 const auto root = ASN1::Object(rawData.begin(), rawData.end());
53 if (root.tag() != V_ASN1_SEQUENCE) {
54 qCWarning(
Log) <<
"wrong ASN1 root node type" << root.tagName();
60 auto outer = root.firstChild();
61 proof.disclosureTime = outer.readInt64();
63 proof.C = outer.readBignum();
65 proof.A = outer.readBignum();
67 proof.EResponse = outer.readBignum();
69 proof.VResponse = outer.readBignum();
71 proof.AResponses.push_back(outer.readBignum());
73 if (outer.tag() != V_ASN1_SEQUENCE) {
74 qCWarning(
Log) <<
"wrong ADisclosed field type" << outer.tagName();
87 auto adisclosed = outer.firstChild();
88 proof.ADisclosed.push_back(adisclosed.readBignum());
93 const auto rawMetaData = nlDecodeAsn1ByteArray(adisclosed);
94 const auto metadata = ASN1::Object(rawMetaData.begin(), rawMetaData.end());
95 if (metadata.tag() != V_ASN1_SEQUENCE) {
96 qCWarning(
Log) <<
"meta data is not a ASN.1 SEQUENCE:" << metadata.tagName();
99 auto metadataEntry = metadata.firstChild();
100 const auto version = metadataEntry.readOctetString();
101 if (
version.size() != 1 || version[0] != 0x02) {
102 qCWarning(
Log) <<
"unsupported version:" <<
version;
105 metadataEntry = metadataEntry.next();
109 adisclosed = adisclosed.next();
110 proof.ADisclosed.push_back(adisclosed.readBignum());
111 const auto rawIsSpecimen = nlDecodeAsn1ByteArray(adisclosed);
112 const bool isSpecimen = rawIsSpecimen.size() != 1 || rawIsSpecimen[0] !=
'0';
113 adisclosed = adisclosed.next();
114 proof.ADisclosed.push_back(adisclosed.readBignum());
117 adisclosed = adisclosed.next();
118 proof.ADisclosed.push_back(adisclosed.readBignum());
120 adisclosed = adisclosed.next();
121 proof.ADisclosed.push_back(adisclosed.readBignum());
122 const auto validTo = validFrom.addSecs(3600 * nlDecodeAsn1ByteArray(adisclosed).toInt());
125 adisclosed = adisclosed.next();
126 proof.ADisclosed.push_back(adisclosed.readBignum());
128 adisclosed = adisclosed.next();
129 proof.ADisclosed.push_back(adisclosed.readBignum());
133 adisclosed = adisclosed.next();
134 proof.ADisclosed.push_back(adisclosed.readBignum());
136 if (!adisclosed.hasNext()) {
137 qCWarning(
Log) <<
"ADisclosed sequence too short";
140 adisclosed = adisclosed.next();
141 proof.ADisclosed.push_back(adisclosed.readBignum());
146 if (proof.isNull()) {
149 const auto publicKey = IrmaPublicKeyLoader::load(issuer);
151 if (publicKey.isValid()) {
152 const auto sigValid = IrmaVerifier::verify(proof, publicKey);
159 if (validFrom.secsTo(validTo) > 48 * 3600) {
161 cert.setCountry(QStringLiteral(
"NL"));
162 cert.setDisease(QStringLiteral(
"COVID-19"));
164 cert.setDateOfBirth(birthday);
165 cert.setCertificateIssueDate(validFrom);
166 cert.setCertificateExpiryDate(validTo);
167 cert.setRawData(data);
173 cert.setCountry(QStringLiteral(
"NL"));
174 cert.setDisease(QStringLiteral(
"COVID-19"));
175 cert.setResult(KTestCertificate::Negative);
177 cert.setDateOfBirth(birthday);
178 cert.setCertificateIssueDate(validFrom);
179 cert.setCertificateExpiryDate(validTo);
180 cert.setRawData(data);
@ ValidSignature
signature is valid
@ InvalidSignature
signature is invalid
@ UnknownSignature
signature verification was attempted but didn't yield a result, e.g. due to a missing certificate of ...
A vaccination certificate.
KDB_EXPORT KDbVersionInfo version()
QString name(StandardAction id)
QByteArray left(qsizetype len) const const
qsizetype size() const const
bool startsWith(QByteArrayView bv) const const
QByteArray toBase64(Base64Options options) const const
QByteArray hash(QByteArrayView data, Algorithm method)
QDate fromString(QStringView string, QStringView format, QCalendar cal)
QDateTime fromSecsSinceEpoch(qint64 secs)
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)