/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 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 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 <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#pragma once

#include <QDateTime>
#include <QList>
#include <QMap>
#include <QPair>
#include <QSslCertificate>

#include "src/datovka_shared/crypto/crypto.h"

class QByteArray; /* Forward declaration. */

/*!
 * @brief Gathers and sorts timestamps from CMS container.
 */
class TstEntries {
private:
	Q_DISABLE_COPY(TstEntries)

public:
	/*!
	 * @brief Data validity outcome.
	 */
	enum Validity {
		MISSING = -1, /*!< No data to validate. */
		INVALID = 0, /*!< Data invalid. */
		VALID = 1 /*!< Data valid. */
	};

	/*!
	 * @brief Constructor.
	 */
	TstEntries(void);

	/*!
	 * @brief Destructor.
	 */
	~TstEntries(void);

	/*!
	 * @brief Manually add a timestamp.
	 *
	 * @param[in] type Timestamp type.
	 * @param[in] tstDer Timestamp data.
	 * @return True on success, false on any error.
	 */
	bool addTst(enum der_data_type type, const QByteArray &tstDER);

	/*!
	 * @brief Collect timestamps from the CM container and add hem to list.
	 *
	 * @param[in] msgDER Binary CMS contained data.
	 * @return True on success, false on any error.
	 */
	bool addCmsTsts(const QByteArray &msgDER);

	/*!
	 * @brief Validate the timestamps, read timestamping time and sort
	 *     archive timestamps.
	 *
	 * @note The method should be called only after finished with adding
	 *     timestamp data.
	 */
	void sortTimestamps(void);

	const struct der_data_list_entry *envelopeTst(void) const;
	bool envelopeTstValid(void) const;
	qint64 envelopeTstTime(void) const;

	const struct der_data_list_entry *signatureTst(void) const;
	bool signatureTstValid(void) const;
	qint64 signatureTstTime(void) const;

	const struct der_data_list_entry *archiveTst(qint64 time) const;
	bool archiveTstValid(qint64 time) const;
	const QList<qint64> &sortedArchiveTstTimes(void) const;

	/*!
	 * @brief Gathers all timestamp data from CMS contained and checks
	 *     whether latest timestamp is valid.
	 *
	 * @note Ignores timestamp in envelope.
	 * @param[in] msgDER Raw message CMS data.
	 * @param[out] tstTime Timestamping time,
	 *                     invalid value on error or if no timestamp could
	 *                     be acquired.
	 * @return VALID if latest timestamp valid, INVALID if invalid,
	 *     MISSING on any error.
	 */
	static
	enum Validity latestTstValid(const QByteArray &msgDER,
	    QDateTime &tstTime);

	/*!
	 * @brief Returns signing certificate inception and expiration date.
	 *
	 * @note Ignores timestamp in envelope.
	 *
	 * @param[in] msgDER Raw message CMS data.
	 * @param[out] incTime Inception time.
	 * @param[out] expTime Expiration time.
	 * @return True on success.
	 */
	static
	bool latestTstSigningCertTimes(const QByteArray &msgDER,
	    QDateTime &incTime, QDateTime &expTime);

	/*!
	 * @brief Check whether certificate expires before specified limit.
	 *
	 * @note Ignores timestamp in envelope.
	 *
	 * @param[in] msgDER Raw message CMS data.
	 * @param[in] days Number of days preceding the deadline.
	 * @param[in] dDate Deadline date.
	 * @return True if certificate expires before specified number of days
	 *     before specified deadline.
	 */
	static
	bool latestTstSigningCertExpiresBefore(const QByteArray &msgDER,
	    int days, const QDateTime &dDate = QDateTime());

private:
	struct der_data_list_entry *m_timeStampList;

	const struct der_data_list_entry *m_envelope_tst;
	bool m_envelope_tst_valid;
	qint64 m_envelope_tst_time;
	const struct der_data_list_entry *m_signature_tst;
	bool m_signature_tst_valid;
	qint64 m_signature_tst_time;
	QMap<qint64, QPair<const struct der_data_list_entry *, bool> > m_archiveTsts;
	QList<qint64> m_sortedArchiveTstTimes;
};

/*!
 * @brief Returns signing certificate of message.
 *
 * @param[in] msgDER Raw message or time stamp data.
 * @param[out] saId Signature algorithm identifier.
 * @param[out] saName Signature algorithm name.
 * @return Null certificate on failure.
 */
QSslCertificate signingCert(const QByteArray &msgDER,
    QString &saId, QString &saName);

/*!
 * @brief Signing certificate issuer information.
 *
 * @param[in] DER Raw message or time stamp data.
 * @param[out] oStr Organisation name.
 * @param[out] ouStr Organisation unit name.
 * @param[out] nStr Common name.
 * @param[out] cStr Country name.
 * @return False on failure.
 */
bool signingCertIssuerInfo(const QByteArray &DER, QString &oStr, QString &ouStr,
    QString &nStr, QString &cStr);

/*!
 * @brief Returns signing certificate inception and expiration date.
 *
 * @param[in] DER Raw message or time stamp data.
 * @param[out] incTime Inception time.
 * @param[out] expTime Expiration time.
 * @return True on success.
 */
bool signingCertTimes(const QByteArray &DER, QDateTime &incTime,
    QDateTime &expTime);

/*!
 * @brief Check whether certificate expires before specified limit.
 *
 * @param[in] DER Raw message or time stamp data.
 * @param[in] days Number of days preceding the deadline.
 * @param[in] dDate Deadline date.
 * @return True if certificate expires before specified number of days
 *     before specified deadline.
 */
bool signingCertExpiresBefore(const QByteArray &DER,
    int days, const QDateTime &dDate = QDateTime());

/*!
 * @brief Return whether signing certificate is valid.
 *
 * @param[in] DER Raw message or time stamp data.
 * @return True is signing certificate was verified successfully.
 */
bool signingCertValid(const QByteArray &DER, struct crt_verif_outcome &cvo);
