File indexing completed on 2024-12-29 04:51:09
0001 /* 0002 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "vdvticketparser.h" 0008 #include "vdvdata_p.h" 0009 #include "vdvcertificate_p.h" 0010 #include "iso9796_2decoder_p.h" 0011 #include "logging.h" 0012 0013 #include "../asn1/berelement.h" 0014 0015 #include <QByteArray> 0016 #include <QDebug> 0017 0018 using namespace KItinerary; 0019 0020 VdvTicketParser::VdvTicketParser() = default; 0021 VdvTicketParser::~VdvTicketParser() = default; 0022 0023 bool VdvTicketParser::parse(const QByteArray &data) 0024 { 0025 // (1) find the certificate authority reference (CAR) to identify the key to decode the CV certificate 0026 const auto sig = BER::TypedElement<TagSignature>(data); 0027 if (!sig.isValid()) { 0028 qCDebug(Log) << "Invalid VDV ticket signature."; 0029 return false; 0030 } 0031 const auto sigRemainder = BER::TypedElement<TagSignatureRemainder>(data, sig.size()); 0032 if (!sigRemainder.isValid()) { 0033 qCDebug(Log) << "Invalid VDV signature remainder."; 0034 return false; 0035 } 0036 0037 const auto cvCertOffset = sig.size() + sigRemainder.size(); 0038 auto cvCert = VdvCertificate(data, cvCertOffset); 0039 if ((!cvCert.isValid() && !cvCert.needsCaKey())) { 0040 qCDebug(Log) << "Invalid CV signature:" << cvCert.isValid() << cvCertOffset << cvCert.size(); 0041 return false; 0042 } 0043 0044 const auto carOffset = cvCertOffset + cvCert.size(); 0045 const auto carBlock = BER::TypedElement<TagCaReference>(data, carOffset); 0046 if (!carBlock.isValid()) { 0047 qCDebug(Log) << "Invalid CA Reference."; 0048 return false; 0049 } 0050 const auto car = carBlock.contentAt<VdvCaReference>(0); 0051 if (!car) { 0052 qCDebug(Log) << "Cannot obtain CA Reference."; 0053 return false; 0054 } 0055 qCDebug(Log) << "CV CAR:" << QByteArray(car->region, 5) << car->serviceIndicator << car->discretionaryData << car->algorithmReference << car->year; 0056 0057 const auto caCert = VdvPkiRepository::caCertificate(car); 0058 if (!caCert.isValid()) { 0059 qCWarning(Log) << "Could not find CA certificate" << QByteArray(reinterpret_cast<const char*>(car), sizeof(VdvCaReference)).toHex(); 0060 return false; 0061 } 0062 0063 // (2) decode the CV certificate 0064 cvCert.setCaCertificate(caCert); 0065 if (!cvCert.isValid()) { 0066 qCWarning(Log) << "Failed to decode CV certificate."; 0067 return false; 0068 } 0069 0070 // (3) decode the ticket data using the decoded CV certificate 0071 Iso9796_2Decoder decoder; 0072 decoder.setRsaParameters(cvCert.modulus(), cvCert.modulusSize(), cvCert.exponent(), cvCert.exponentSize()); 0073 decoder.addWithRecoveredMessage(sig.contentData(), sig.contentSize()); 0074 decoder.add(sigRemainder.contentData(), sigRemainder.contentSize()); 0075 0076 // (4) profit! 0077 m_ticket = VdvTicket(decoder.recoveredMessage(), data); 0078 return true; 0079 } 0080 0081 bool VdvTicketParser::maybeVdvTicket(const QByteArray& data) 0082 { 0083 if (data.size() < 352) { 0084 return false; 0085 } 0086 0087 // signature header 0088 const auto sig = BER::TypedElement<TagSignature>(data); 0089 if (!sig.isValid()) { 0090 return false; 0091 } 0092 const auto rem = BER::TypedElement<TagSignatureRemainder>(data, sig.size()); 0093 if (!rem.isValid()) { 0094 return false; 0095 } 0096 0097 // verify the "VDV" marker is there 0098 return strncmp((const char*)(rem.contentData() + rem.contentSize() - 5), "VDV", 3) == 0; 0099 } 0100 0101 VdvTicket VdvTicketParser::ticket() const 0102 { 0103 return m_ticket; 0104 }