diff --git a/CMakeLists.txt b/CMakeLists.txt index 8223e2b..2717353 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,123 +1,128 @@ cmake_minimum_required(VERSION 3.5) set(PIM_VERSION "5.13.40") project(KItinerary VERSION ${PIM_VERSION}) set(CMAKE_CXX_STANDARD 14) set(KF5_MIN_VERSION "5.64.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMAddTests) include(ECMGenerateHeaders) include(ECMQtDeclareLoggingCategory) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(GenerateExportHeader) ecm_setup_version(PROJECT VARIABLE_PREFIX KITINERARY VERSION_HEADER kitinerary_version.h PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfigVersion.cmake" ) set(QT_REQUIRED_VERSION "5.12.0") find_package(Qt5 ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Gui Qml) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS I18n) if (NOT ANDROID) find_package(SharedMimeInfo 1.3 REQUIRED) endif() set(KMIME_VERSION "5.13.40") set(PIM_PKPASS "5.13.40") find_package(KF5Mime ${KMIME_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KF5_MIN_VERSION} CONFIG) find_package(KF5Contacts ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KPimPkPass ${PIM_PKPASS} CONFIG REQUIRED) find_package(Poppler COMPONENTS Core) set_package_properties("Poppler" PROPERTIES TYPE OPTIONAL PURPOSE "Support for extraction from PDF booking confirmations.") find_package(ZXing CONFIG) set_package_properties("ZXing" PROPERTIES TYPE OPTIONAL PURPOSE "Support for barcode decoding." URL "https://github.com/nu-book/zxing-cpp") find_package(ZLIB REQUIRED) set_package_properties("ZLIB" PROPERTIES PURPOSE "Support for decoding UIC 918-3 train tickets.") find_package(LibXml2 MODULE) set_package_properties("LibXml2" PROPERTIES PURPOSE "Support for extraction from HTML booking confirmations." URL "http://libxml.org") find_package(PhoneNumber OPTIONAL_COMPONENTS PhoneNumber QUIET) set_package_properties("PhoneNumber" PROPERTIES PURPOSE "Parsing and geo-coding of phone numbers.") +find_package(OpenSSL 1.1) +set_package_properties("OpenSSL" PROPERTIES TYPE OPTIONAL PURPOSE "VDV ticket decoding." URL "https://openssl.org") if (NOT ANDROID) set_package_properties(KF5CalendarCore PROPERTIES TYPE REQUIRED) set_package_properties(LibXml2 PROPERTIES TYPE REQUIRED) endif() if(TARGET Poppler::Core) # check if we have private Poppler headers find_file(HAVE_POPPLER_UNSTABLE_HEADERS "OutputDev.h" PATHS ${Poppler_INCLUDE_DIRS} NO_DEFAULT_PATH) if (NOT HAVE_POPPLER_UNSTABLE_HEADERS) message(WARNING "Poppler was not build with ENABLE_UNSTABLE_API_ABI_HEADER - building without PDF support!") set(HAVE_POPPLER FALSE) else() set(HAVE_POPPLER TRUE) endif() endif() if (HAVE_POPPLER) string(REPLACE "." ";" _poppler_version_components ${Poppler_VERSION}) list(GET _poppler_version_components 0 POPPLER_VERSION_MAJOR) list(GET _poppler_version_components 1 POPPLER_VERSION_MINOR) list(GET _poppler_version_components 2 POPPLER_VERSION_PATCH) endif() if (TARGET ZXing::Core) set(HAVE_ZXING ON) endif() if (TARGET KF5::CalendarCore) set(HAVE_KCAL ON) endif() if (LIBXML2_FOUND) set(HAVE_LIBXML2 ON) endif() if (TARGET PhoneNumber::PhoneNumber) set(HAVE_PHONENUMBER ON) endif() +if (TARGET OpenSSL::Crypto) + set(HAVE_OPENSSL_RSA ON) +endif() add_definitions(-DTRANSLATION_DOMAIN=\"kitinerary\") if (EXISTS "${CMAKE_SOURCE_DIR}/.git") add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x060000) endif() add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(autotests) endif() feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KPimItinerary") configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KPimItineraryConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel) install(EXPORT KPimItineraryTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KPimItineraryTargets.cmake NAMESPACE KPim:: ) install(FILES org_kde_kitinerary.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6d187ae..5c778a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,236 +1,239 @@ set(KDE_INSTALL_INCLUDEDIR_PIM ${KDE_INSTALL_INCLUDEDIR}/KPim) add_subdirectory(cli) if (TARGET Qt5::Network) add_subdirectory(knowledgedb-generator) endif() configure_file(config-kitinerary.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kitinerary.h) set(kitinerary_lib_srcs datatypes/action.cpp datatypes/brand.cpp datatypes/bustrip.cpp datatypes/creativework.cpp datatypes/event.cpp datatypes/flight.cpp datatypes/organization.cpp datatypes/person.cpp datatypes/place.cpp datatypes/reservation.cpp datatypes/taxi.cpp datatypes/ticket.cpp datatypes/traintrip.cpp datatypes/rentalcar.cpp datatypes/visit.cpp generic/genericpdfextractor.cpp generic/genericpkpassextractor.cpp generic/genericuic918extractor.cpp generic/structureddataextractor.cpp jsapi/barcode.cpp jsapi/bitarray.cpp jsapi/context.cpp jsapi/jsonld.cpp knowledgedb/alphaid.cpp knowledgedb/airportdb.cpp knowledgedb/countrydb.cpp knowledgedb/iatacode.cpp knowledgedb/knowledgedb.cpp knowledgedb/timezonedb.cpp knowledgedb/trainstationdb.cpp pdf/pdfdocument.cpp pdf/pdfextractoroutputdevice.cpp pdf/pdfimage.cpp pdf/pdfvectorpicture.cpp pdf/popplerglobalparams.cpp pdf/popplerutils.cpp uic9183/rct2ticket.cpp uic9183/uic9183block.cpp uic9183/uic9183parser.cpp uic9183/uic9183ticketlayout.cpp uic9183/vendor0080block.cpp vdv/iso9796_2decoder.cpp vdv/vdvcertificate.cpp vdv/vdvticketparser.cpp vdv/certs/vdv-certs.qrc barcodedecoder.cpp calendarhandler.cpp documentutil.cpp extractor.cpp extractorengine.cpp extractorfilter.cpp extractorinput.cpp extractorpostprocessor.cpp extractorrepository.cpp extractorutil.cpp extractorvalidator.cpp file.cpp flightpostprocessor.cpp htmldocument.cpp iatabcbpparser.cpp jsonlddocument.cpp jsonldimportfilter.cpp locationutil.cpp mergeutil.cpp qimagepurebinarizer.cpp sortutil.cpp stringutil.cpp ) qt5_add_resources(kitinerary_lib_srcs extractors/extractors.qrc) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER logging.h IDENTIFIER KItinerary::Log CATEGORY_NAME org.kde.kitinerary) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER compare-logging.h IDENTIFIER KItinerary::CompareLog CATEGORY_NAME org.kde.kitinerary.comparator) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER validator-logging.h IDENTIFIER KItinerary::ValidatorLog CATEGORY_NAME org.kde.kitinerary.extractorValidator) add_library(KPimItinerary ${kitinerary_lib_srcs}) add_library(KPim::Itinerary ALIAS KPimItinerary) generate_export_header(KPimItinerary BASE_NAME KItinerary) set_target_properties(KPimItinerary PROPERTIES VERSION ${KITINERARY_VERSION_STRING} SOVERSION ${KITINERARY_SOVERSION} EXPORT_NAME Itinerary ) target_include_directories(KPimItinerary INTERFACE "$") target_include_directories(KPimItinerary PUBLIC "$") target_link_libraries(KPimItinerary PUBLIC Qt5::Core KF5::Mime PRIVATE Qt5::Qml KF5::Archive KF5::I18n KF5::Contacts KPim::PkPass ${ZLIB_LIBRARIES} ) if (HAVE_POPPLER) target_link_libraries(KPimItinerary PRIVATE Poppler::Core) endif() if (HAVE_ZXING) target_link_libraries(KPimItinerary PRIVATE ZXing::Core) endif() if (HAVE_KCAL) target_link_libraries(KPimItinerary PUBLIC KF5::CalendarCore) endif() if (HAVE_LIBXML2) target_compile_definitions(KPimItinerary PRIVATE ${LIBXML2_DEFINITIONS}) target_include_directories(KPimItinerary PRIVATE ${LIBXML2_INCLUDE_DIR}) target_link_libraries(KPimItinerary PRIVATE ${LIBXML2_LIBRARIES}) endif() if (HAVE_PHONENUMBER) target_link_libraries(KPimItinerary PRIVATE PhoneNumber::PhoneNumber) endif() +if (HAVE_OPENSSL_RSA) + target_link_libraries(KPimItinerary PRIVATE OpenSSL::Crypto) +endif() ecm_generate_headers(KItinerary_FORWARDING_HEADERS HEADER_NAMES BarcodeDecoder CalendarHandler DocumentUtil Extractor ExtractorEngine ExtractorFilter ExtractorInput ExtractorPostprocessor ExtractorRepository File HtmlDocument IataBcbpParser JsonLdDocument LocationUtil MergeUtil SortUtil PREFIX KItinerary REQUIRED_HEADERS KItinerary_HEADERS ) ecm_generate_headers(KItinerary_KnowledgeDb_FORWARDING_HEADERS HEADER_NAMES AlphaId CountryDb KnowledgeDb PREFIX KItinerary REQUIRED_HEADERS KItinerary_KnowledgeDb_HEADERS RELATIVE knowledgedb ) ecm_generate_headers(KItinerary_Datatypes_FORWARDING_HEADERS HEADER_NAMES Action Brand BusTrip CreativeWork Datatypes Event Flight Organization Reservation RentalCar Person Place Taxi Ticket TrainTrip Visit PREFIX KItinerary REQUIRED_HEADERS KItinerary_Datatypes_HEADERS RELATIVE datatypes ) ecm_generate_headers(KItinerary_Pdf_FORWARDING_HEADERS HEADER_NAMES PdfDocument PdfImage PREFIX KItinerary REQUIRED_HEADERS KItinerary_Pdf_HEADERS RELATIVE pdf ) ecm_generate_headers(KItinerary_Uic9183_FORWARDING_HEADERS HEADER_NAMES Rct2Ticket Uic9183Block Uic9183Parser Uic9183TicketLayout Vendor0080Block PREFIX KItinerary REQUIRED_HEADERS KItinerary_Uic9183_HEADERS RELATIVE uic9183 ) ecm_generate_headers(KItinerary_Vdv_FORWARDING_HEADERS HEADER_NAMES VdvTicketParser PREFIX KItinerary REQUIRED_HEADERS KItinerary_Vdv_HEADERS RELATIVE vdv ) install(TARGETS KPimItinerary EXPORT KPimItineraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KItinerary_FORWARDING_HEADERS} ${KItinerary_KnowledgeDb_FORWARDING_HEADERS} ${KItinerary_Datatypes_FORWARDING_HEADERS} ${KItinerary_Pdf_FORWARDING_HEADERS} ${KItinerary_Uic9183_FORWARDING_HEADERS} ${KItinerary_Vdv_FORWARDING_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/KItinerary ) install(FILES ${KItinerary_HEADERS} ${KItinerary_AirportDb_HEADERS} ${KItinerary_Datatypes_HEADERS} ${KItinerary_KnowledgeDb_HEADERS} ${KItinerary_Pdf_HEADERS} ${KItinerary_Uic9183_HEADERS} ${KItinerary_Vdv_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kitinerary_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/kitinerary ) if (NOT ANDROID) install(FILES application-vnd-kde-itinerary.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) endif() diff --git a/src/config-kitinerary.h.cmake b/src/config-kitinerary.h.cmake index e5b4bc9..7a5678a 100644 --- a/src/config-kitinerary.h.cmake +++ b/src/config-kitinerary.h.cmake @@ -1,39 +1,40 @@ /* Copyright (c) 2017 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CONFIG_KITINERARY_H #define CONFIG_KITINERARY_H #cmakedefine HAVE_POPPLER // namespaced by "K" to not interfere with defines poppler provides itself #define KPOPPLER_VERSION_STRING "@Poppler_VERSION@" #define KPOPPLER_VERSION_MAJOR @POPPLER_VERSION_MAJOR@ #define KPOPPLER_VERSION_MINOR @POPPLER_VERSION_MINOR@ #define KPOPPLER_VERSION_PATCH @POPPLER_VERSION_PATCH@ #define KPOPPLER_VERSION ((@POPPLER_VERSION_MAJOR@<<16)|(@POPPLER_VERSION_MINOR@<<8)|(@POPPLER_VERSION_PATCH@)) #cmakedefine HAVE_ZXING #cmakedefine HAVE_KCAL #cmakedefine HAVE_LIBXML2 #cmakedefine HAVE_PHONENUMBER +#cmakedefine HAVE_OPENSSL_RSA #define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}" #endif diff --git a/src/vdv/iso9796_2decoder.cpp b/src/vdv/iso9796_2decoder.cpp index 243a676..1446cc6 100644 --- a/src/vdv/iso9796_2decoder.cpp +++ b/src/vdv/iso9796_2decoder.cpp @@ -1,61 +1,78 @@ /* Copyright (C) 2019 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "config-kitinerary.h" #include "iso9796_2decoder_p.h" +#include + +#ifdef HAVE_OPENSSL_RSA +#include +#endif + using namespace KItinerary; -Iso9796_2Decoder::Iso9796_2Decoder() = default; +Iso9796_2Decoder::Iso9796_2Decoder() +#ifdef HAVE_OPENSSL_RSA + : m_rsa(RSA_new(), RSA_free) +#endif +{ +} + Iso9796_2Decoder::~Iso9796_2Decoder() = default; void Iso9796_2Decoder::setRsaParameters(const uint8_t *modulus, uint16_t modulusSize, const uint8_t *exponent, uint16_t exponentSize) { #ifdef HAVE_OPENSSL_RSA - // TODO + const auto n = BN_bin2bn(modulus, modulusSize, nullptr); + const auto e = BN_bin2bn(exponent, exponentSize, nullptr); + RSA_set0_key(m_rsa.get(), n, e, nullptr); // takes ownership of n and e #else Q_UNUSED(modulus); Q_UNUSED(modulusSize); Q_UNUSED(exponent); Q_UNUSED(exponentSize); #endif } void Iso9796_2Decoder::addWithRecoveredMessage(const uint8_t *data, int size) { #ifdef HAVE_OPENSSL_RSA - // TODO + QByteArray out; + out.resize(RSA_size(m_rsa.get())); + const auto outSize = RSA_public_decrypt(size, data, (uint8_t*)out.data(), m_rsa.get(), RSA_NO_PADDING); + out.resize(outSize); + qDebug() << outSize << out.toHex(); #else Q_UNUSED(data); Q_UNUSED(size); #endif } void Iso9796_2Decoder::add(const uint8_t *data, int size) { #ifdef HAVE_OPENSSL_RSA // TODO #else Q_UNUSED(data); Q_UNUSED(size); #endif } QByteArray Iso9796_2Decoder::recoveredMessage() const { return {}; // TODO } diff --git a/src/vdv/iso9796_2decoder_p.h b/src/vdv/iso9796_2decoder_p.h index b954238..9aa93e7 100644 --- a/src/vdv/iso9796_2decoder_p.h +++ b/src/vdv/iso9796_2decoder_p.h @@ -1,50 +1,60 @@ /* Copyright (C) 2019 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KITINERARY_ISO9796_2DECODER_P_H #define KITINERARY_ISO9796_2DECODER_P_H +#include "config-kitinerary.h" + #include +#ifdef HAVE_OPENSSL_RSA +#include +#endif + #include +#include namespace KItinerary { /** Message recovery for ISO 9796-2 Schema 1 signatures. * This does not care at all about security or actually validating the signature, * this is merely about recoverying the part of the signed message that is mangled * by the signature. */ class Iso9796_2Decoder { public: Iso9796_2Decoder(); ~Iso9796_2Decoder(); void setRsaParameters(const uint8_t *modulus, uint16_t modulusSize, const uint8_t *exponent, uint16_t exponentSize); void addWithRecoveredMessage(const uint8_t *data, int size); void add(const uint8_t *data, int size); QByteArray recoveredMessage() const; private: +#ifdef HAVE_OPENSSL_RSA + std::unique_ptr m_rsa; +#endif }; } #endif // KITINERARY_ISO9796_2DECODER_P_H diff --git a/src/vdv/vdvticketparser.cpp b/src/vdv/vdvticketparser.cpp index e9fe2f5..dcd1a17 100644 --- a/src/vdv/vdvticketparser.cpp +++ b/src/vdv/vdvticketparser.cpp @@ -1,114 +1,119 @@ /* Copyright (C) 2019 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "vdvticketparser.h" #include "vdvdata_p.h" #include "vdvcertificate_p.h" #include "iso9796_2decoder_p.h" #include #include using namespace KItinerary; VdvTicketParser::VdvTicketParser() = default; VdvTicketParser::~VdvTicketParser() = default; void VdvTicketParser::parse(const QByteArray &data) { qDebug() << data.size(); if (!maybeVdvTicket(data)) { qWarning() << "Input data is not a VDV ticket!"; return; } // (1) find the certificate authority reference (CAR) to identify the key to decode the CV certificate const auto sigRemainder = reinterpret_cast(data.constData() + VdvSignatureRemainder::Offset); if (!sigRemainder->isValid() || VdvSignatureRemainder::Offset + sigRemainder->size() + sizeof(VdvCertificateHeader) > (unsigned)data.size()) { qWarning() << "Invalid VDV signature remainder."; return; } qDebug() << sigRemainder->contentSize(); const auto cvCertOffset = VdvSignatureRemainder::Offset + sigRemainder->size(); const auto cvCert = reinterpret_cast(data.constData() + cvCertOffset); if (!cvCert->isValid() || cvCertOffset + cvCert->size() + sizeof(VdvCaReferenceBlock) > (unsigned)data.size()) { qWarning() << "Invalid CV signature:" << cvCert->isValid() << cvCertOffset << cvCert->size(); return; } qDebug() << cvCert->contentSize(); const auto carOffset = cvCertOffset + cvCert->size(); const auto carBlock = reinterpret_cast(data.constData() + carOffset); if (!carBlock->isValid() || carBlock->contentSize() < sizeof(VdvCaReference)) { qWarning() << "Invalid CA Reference."; return; } const auto car = carBlock->contentAt(0); qDebug() << QByteArray(car->name, 3) << car->serviceIndicator << car->discretionaryData << car->algorithmReference << car->year; const auto caCert = VdvPkiRepository::caCertificate(car->algorithmReference); if (!caCert.isValid()) { qWarning() << "Could not find CA certificate" << car->algorithmReference; return; } // (2) decode the CV certificate const auto cvSig = cvCert->contentAt(0); if (!cvSig->isValid()) { qWarning() << "Invalid CV certificate signature structure."; return; } qDebug() << cvCert->contentSize() << cvSig->size() << (uint8_t)*(cvCert->contentData() + cvSig->size()); const auto cvRem = cvCert->contentAt(cvSig->size()); if (!cvRem->isValid()) { qWarning() << "Invalid CV certificate signature remainder structure."; return; } qDebug() << cvSig->contentSize() << cvRem->contentSize(); Iso9796_2Decoder cvDecoder; cvDecoder.setRsaParameters(caCert.modulus(), caCert.modulusSize(), caCert.exponent(), caCert.exponentSize()); cvDecoder.addWithRecoveredMessage(cvSig->contentData(), cvSig->contentSize()); cvDecoder.add(cvRem->contentData(), cvRem->contentSize()); + const auto cvDecoded = cvDecoder.recoveredMessage(); + if (cvDecoded.isEmpty()) { + qDebug() << "Failed to decode CV certificate."; + return; + } // (3) decode the ticket data using the decoded CV certificate // TODO // (4) profit! // TODO } bool VdvTicketParser::maybeVdvTicket(const QByteArray& data) { if (data.size() < 352) { return false; } // signature header if ((uint8_t)data[0] != TagSignature || (uint8_t)data[1] != 0x81 || (uint8_t)data[2] != 0x80 || (uint8_t)data[VdvSignatureRemainder::Offset] != TagSignatureRemainder) { return false; } const uint8_t len = data[132]; // length of the 0x9A unsigned data block if (len + 133 > data.size()) { return false; } // verify the "VDV" marker is there return strncmp(data.constData() + 133 + len - 5, "VDV", 3) == 0; }