7#include "dkimchecksignaturejob.h" 
    8#include "dkimdownloadkeyjob.h" 
   10#include "dkimkeyrecord.h" 
   11#include "dkimmanagerkey.h" 
   13#include "messageviewer_dkimcheckerdebug.h" 
   15#include <KEmailAddress> 
   16#include <QCryptographicHash> 
   19#include <QRegularExpression> 
   21#include <openssl/bn.h> 
   22#include <openssl/core_names.h> 
   23#include <openssl/decoder.h> 
   24#include <openssl/err.h> 
   25#include <openssl/evp.h> 
   26#include <openssl/rsa.h> 
   30using namespace MessageViewer;
 
   31DKIMCheckSignatureJob::DKIMCheckSignatureJob(
QObject *parent)
 
   36DKIMCheckSignatureJob::~DKIMCheckSignatureJob() = 
default;
 
   38MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult DKIMCheckSignatureJob::createCheckResult()
 const 
   40    MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult result;
 
   41    result.error = mError;
 
   42    result.warning = mWarning;
 
   43    result.status = mStatus;
 
   44    result.sdid = mDkimInfo.domain();
 
   45    result.auid = mDkimInfo.agentOrUserIdentifier();
 
   46    result.fromEmail = mFromEmail;
 
   47    result.listSignatureAuthenticationResult = mCheckSignatureAuthenticationResult;
 
   51QString DKIMCheckSignatureJob::bodyCanonizationResult()
 const 
   53    return mBodyCanonizationResult;
 
   56QString DKIMCheckSignatureJob::headerCanonizationResult()
 const 
   58    return mHeaderCanonizationResult;
 
   61void DKIMCheckSignatureJob::start()
 
   64        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Item has not a message";
 
   65        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
   66        Q_EMIT result(createCheckResult());
 
   70    if (
auto hrd = mMessage->headerByType(
"DKIM-Signature")) {
 
   71        mDkimValue = hrd->asUnicodeString();
 
   74    if (
auto hrd = mMessage->from(
false)) {
 
   77    if (mDkimValue.isEmpty()) {
 
   78        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::EmailNotSigned;
 
   79        Q_EMIT result(createCheckResult());
 
   83    qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"mFromEmail " << mFromEmail;
 
   84    if (!mDkimInfo.parseDKIM(mDkimValue)) {
 
   85        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Impossible to parse header" << mDkimValue;
 
   86        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
   87        Q_EMIT result(createCheckResult());
 
   92    const MessageViewer::DKIMCheckSignatureJob::DKIMStatus status = checkSignature(mDkimInfo);
 
   93    if (status != MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid) {
 
   95        Q_EMIT result(createCheckResult());
 
  100    switch (mDkimInfo.bodyCanonization()) {
 
  101    case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
 
  102        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyCanonicalization;
 
  103        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  104        Q_EMIT result(createCheckResult());
 
  107    case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
 
  108        mBodyCanonizationResult = bodyCanonizationSimple();
 
  110    case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
 
  111        mBodyCanonizationResult = bodyCanonizationRelaxed();
 
  116    if (mDkimInfo.bodyLengthCount() != -1) { 
 
  117        if (mDkimInfo.bodyLengthCount() > mBodyCanonizationResult.length()) {
 
  119            qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
" mDkimInfo.bodyLengthCount() " << mDkimInfo.bodyLengthCount() << 
" mBodyCanonizationResult.length() " 
  120                                                   << mBodyCanonizationResult.length();
 
  121            mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::SignatureTooLarge;
 
  122            mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  123            Q_EMIT result(createCheckResult());
 
  126        } 
else if (mDkimInfo.bodyLengthCount() < mBodyCanonizationResult.length()) {
 
  127            mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::SignatureTooSmall;
 
  130        mBodyCanonizationResult = mBodyCanonizationResult.left(mDkimInfo.bodyLengthCount());
 
  132    if (mBodyCanonizationResult.startsWith(QLatin1StringView(
"\r\n"))) { 
 
  133        mBodyCanonizationResult = mBodyCanonizationResult.right(mBodyCanonizationResult.length() - 2);
 
  136    if (mBodyCanonizationResult.startsWith(QLatin1StringView(
" This is a multi-part message in MIME format"))) { 
 
  137        mBodyCanonizationResult.replace(QStringLiteral(
" This is a multi-part message in MIME format"),
 
  138                                        QStringLiteral(
"This is a multi-part message in MIME format"));
 
  141    if (mBodyCanonizationResult.startsWith(QLatin1StringView(
" This is a cryptographically signed message in MIME format."))) { 
 
  142        mBodyCanonizationResult.replace(QStringLiteral(
" This is a cryptographically signed message in MIME format."),
 
  143                                        QStringLiteral(
"This is a cryptographically signed message in MIME format."));
 
  145    if (mBodyCanonizationResult.startsWith(QLatin1StringView(
" \r\n"))) { 
 
  146        static const QRegularExpression reg{QStringLiteral(
"^ \r\n")};
 
  147        mBodyCanonizationResult.remove(reg);
 
  149#ifdef DEBUG_SIGNATURE_DKIM 
  150    QFile caFile(QStringLiteral(
"/tmp/bodycanon-kmail.txt"));
 
  152    QTextStream outStream(&caFile);
 
  153    outStream << mBodyCanonizationResult;
 
  157    QByteArray resultHash;
 
  158    switch (mDkimInfo.hashingAlgorithm()) {
 
  159    case DKIMInfo::HashingAlgorithmType::Sha1:
 
  162    case DKIMInfo::HashingAlgorithmType::Sha256:
 
  165    case DKIMInfo::HashingAlgorithmType::Any:
 
  166    case DKIMInfo::HashingAlgorithmType::Unknown:
 
  167        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InsupportedHashAlgorithm;
 
  168        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  169        Q_EMIT result(createCheckResult());
 
  175    qDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"resultHash " << resultHash << 
"mDkimInfo.bodyHash()" << mDkimInfo.bodyHash();
 
  176    if (resultHash != mDkimInfo.bodyHash().toLatin1()) {
 
  177        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
" Corrupted body hash";
 
  178        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::CorruptedBodyHash;
 
  179        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  180        Q_EMIT result(createCheckResult());
 
  185    if (mDkimInfo.headerCanonization() == MessageViewer::DKIMInfo::CanonicalizationType::Unknown) {
 
  186        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidHeaderCanonicalization;
 
  187        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  188        Q_EMIT result(createCheckResult());
 
  193    if (!mHeaderParser.wasAlreadyParsed()) {
 
  194        mHeaderParser.setHead(mMessage->head());
 
  195        mHeaderParser.parse();
 
  198    computeHeaderCanonization(
true);
 
  199    if (mPolicy.saveKey() == MessageViewer::MessageViewerSettings::EnumSaveKey::Save) {
 
  200        const QString keyValue = MessageViewer::DKIMManagerKey::self()->keyValue(mDkimInfo.selector(), mDkimInfo.domain());
 
  203            downloadKey(mDkimInfo);
 
  205            parseDKIMKeyRecord(keyValue, mDkimInfo.domain(), mDkimInfo.selector(), 
false);
 
  206            MessageViewer::DKIMManagerKey::self()->updateLastUsed(mDkimInfo.domain(), mDkimInfo.selector());
 
  209        downloadKey(mDkimInfo);
 
  213void DKIMCheckSignatureJob::computeHeaderCanonization(
bool removeQuoteOnContentType)
 
  216    switch (mDkimInfo.headerCanonization()) {
 
  217    case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
 
  219    case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
 
  220        mHeaderCanonizationResult = headerCanonizationSimple();
 
  222    case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
 
  223        mHeaderCanonizationResult = headerCanonizationRelaxed(removeQuoteOnContentType);
 
  246    QString dkimValue = mDkimValue;
 
  247    dkimValue = dkimValue.left(dkimValue.indexOf(QLatin1StringView(
"b=")) + 2);
 
  248    switch (mDkimInfo.headerCanonization()) {
 
  249    case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
 
  251    case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
 
  252        mHeaderCanonizationResult += QLatin1StringView(
"\r\n") + MessageViewer::DKIMUtil::headerCanonizationSimple(QStringLiteral(
"dkim-signature"), dkimValue);
 
  254    case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
 
  255        mHeaderCanonizationResult += QLatin1StringView(
"\r\n")
 
  256            + MessageViewer::DKIMUtil::headerCanonizationRelaxed(QStringLiteral(
"dkim-signature"), dkimValue, removeQuoteOnContentType);
 
  259#ifdef DEBUG_SIGNATURE_DKIM 
  261        QStringLiteral(
"/tmp/headercanon-kmail-%1.txt").arg(removeQuoteOnContentType ? QLatin1StringView(
"removequote") : QLatin1StringView(
"withquote")));
 
  263    QTextStream outHeaderStream(&headerFile);
 
  264    outHeaderStream << mHeaderCanonizationResult;
 
  269void DKIMCheckSignatureJob::setHeaderParser(
const DKIMHeaderParser &headerParser)
 
  271    mHeaderParser = headerParser;
 
  274void DKIMCheckSignatureJob::setCheckSignatureAuthenticationResult(
const QList<DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult> &lst)
 
  276    mCheckSignatureAuthenticationResult = lst;
 
  279QString DKIMCheckSignatureJob::bodyCanonizationSimple()
 const 
  296    return MessageViewer::DKIMUtil::bodyCanonizationSimple(
QString::fromLatin1(mMessage->encodedBody()));
 
  299QString DKIMCheckSignatureJob::bodyCanonizationRelaxed()
 const 
  320    const QString returnValue = MessageViewer::DKIMUtil::bodyCanonizationRelaxed(
QString::fromLatin1(mMessage->encodedBody()));
 
  324QString DKIMCheckSignatureJob::headerCanonizationSimple()
 const 
  328    DKIMHeaderParser parser = mHeaderParser;
 
  330    const auto listSignedHeader{mDkimInfo.listSignedHeader()};
 
  331    for (
const QString &header : listSignedHeader) {
 
  332        const QString str = parser.headerType(header.toLower());
 
  335                headers += QLatin1StringView(
"\r\n");
 
  337            headers += MessageViewer::DKIMUtil::headerCanonizationSimple(header, str);
 
  343QString DKIMCheckSignatureJob::headerCanonizationRelaxed(
bool removeQuoteOnContentType)
 const 
  369    DKIMHeaderParser parser = mHeaderParser;
 
  370    const auto listSignedHeader = mDkimInfo.listSignedHeader();
 
  371    for (
const QString &header : listSignedHeader) {
 
  372        const QString str = parser.headerType(header.toLower());
 
  375                headers += QLatin1StringView(
"\r\n");
 
  377            headers += MessageViewer::DKIMUtil::headerCanonizationRelaxed(header, str, removeQuoteOnContentType);
 
  383void DKIMCheckSignatureJob::downloadKey(
const DKIMInfo &info)
 
  385    auto job = 
new DKIMDownloadKeyJob(
this);
 
  386    job->setDomainName(info.domain());
 
  387    job->setSelectorName(info.selector());
 
  388    connect(job, &DKIMDownloadKeyJob::error, 
this, [
this](
const QString &errorString) {
 
  389        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Impossible to start downloadkey: error returned: " << 
errorString;
 
  390        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey;
 
  391        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  392        Q_EMIT result(createCheckResult());
 
  395    connect(job, &DKIMDownloadKeyJob::success, 
this, &DKIMCheckSignatureJob::slotDownloadKeyDone);
 
  398        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Impossible to start downloadkey";
 
  399        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey;
 
  400        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  401        Q_EMIT result(createCheckResult());
 
  406void DKIMCheckSignatureJob::slotDownloadKeyDone(
const QList<QByteArray> &lst, 
const QString &domain, 
const QString &selector)
 
  409    if (lst.
count() != 1) {
 
  410        for (
const QByteArray &b : lst) {
 
  420void DKIMCheckSignatureJob::parseDKIMKeyRecord(
const QString &str, 
const QString &domain, 
const QString &selector, 
bool storeKeyValue)
 
  422    qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG)
 
  423        << 
"void DKIMCheckSignatureJob::parseDKIMKeyRecord(const QString &str, const QString &domain, const QString &selector, bool storeKeyValue) key:" << str;
 
  424    if (!mDkimKeyRecord.parseKey(str)) {
 
  425        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Impossible to parse key record " << str;
 
  426        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  427        Q_EMIT result(createCheckResult());
 
  431    const QString keyType{mDkimKeyRecord.keyType()};
 
  432    if ((keyType != QLatin1StringView(
"rsa")) && (keyType != QLatin1StringView(
"ed25519"))) {
 
  433        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"mDkimKeyRecord key type is unknown " << keyType << 
" str " << str;
 
  434        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  435        Q_EMIT result(createCheckResult());
 
  442    if (mDkimKeyRecord.flags().contains(QLatin1StringView(
"s"))) {
 
  448        if (mDkimInfo.iDomain() != mDkimInfo.domain()) {
 
  449            mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  450            mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainI;
 
  451            Q_EMIT result(createCheckResult());
 
  459    if (mDkimKeyRecord.flags().contains(QLatin1StringView(
"y"))) {
 
  460        if (!mPolicy.verifySignatureWhenOnlyTest()) {
 
  461            qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Testing mode!";
 
  462            mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::TestKeyMode;
 
  463            mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  464            Q_EMIT result(createCheckResult());
 
  469    if (mDkimKeyRecord.publicKey().isEmpty()) {
 
  471        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"mDkimKeyRecord public key is empty. It was revoked ";
 
  472        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyWasRevoked;
 
  473        mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  474        Q_EMIT result(createCheckResult());
 
  480        Q_EMIT storeKey(str, domain, selector);
 
  486void DKIMCheckSignatureJob::verifySignature()
 
  488    const QString keyType{mDkimKeyRecord.keyType()};
 
  489    if (keyType == QLatin1StringView(
"rsa")) {
 
  490        verifyRSASignature();
 
  491    } 
else if (keyType == QLatin1StringView(
"ed25519")) {
 
  492        verifyEd25519Signature();
 
  494        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
" It's a bug " << keyType;
 
  498void DKIMCheckSignatureJob::verifyEd25519Signature()
 
  501    qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"it's a Ed25519 signed email";
 
  502    mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyConversionError;
 
  503    mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  504    Q_EMIT result(createCheckResult());
 
  508using EVPPKeyPtr = std::unique_ptr<EVP_PKEY, 
decltype(&EVP_PKEY_free)>;
 
  510static EVPPKeyPtr loadRSAPublicKey(
const QByteArray &der)
 
  512    EVP_PKEY *pubKey = 
nullptr;
 
  513    std::unique_ptr<OSSL_DECODER_CTX, 
decltype(&OSSL_DECODER_CTX_free)> decoderCtx(
 
  514        OSSL_DECODER_CTX_new_for_pkey(&pubKey, 
"DER", 
nullptr, 
"RSA", EVP_PKEY_PUBLIC_KEY, 
nullptr, 
nullptr),
 
  515        OSSL_DECODER_CTX_free);
 
  517        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Failed to create OSSL_DECODER_CTX";
 
  518        return {
nullptr, EVP_PKEY_free};
 
  522    std::unique_ptr<BIO, 
decltype(&BIO_free)> pubKeyBio(BIO_new_mem_buf(rawDer.constData(), rawDer.size()), BIO_free);
 
  523    if (!OSSL_DECODER_from_bio(decoderCtx.get(), pubKeyBio.get())) {
 
  525        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Failed to decode public key:" << ERR_error_string(ERR_get_error(), 
nullptr);
 
  526        return {
nullptr, EVP_PKEY_free};
 
  529    return {pubKey, EVP_PKEY_free};
 
  532static const EVP_MD *evpAlgo(DKIMInfo::HashingAlgorithmType algo)
 
  535    case DKIMInfo::HashingAlgorithmType::Sha1:
 
  537    case DKIMInfo::HashingAlgorithmType::Sha256:
 
  539    case DKIMInfo::HashingAlgorithmType::Any:
 
  540    case DKIMInfo::HashingAlgorithmType::Unknown:
 
  546static std::optional<bool> doVerifySignature(EVP_PKEY *key, 
const EVP_MD *md, 
const QByteArray &signature, 
const QByteArray &message)
 
  548    std::unique_ptr<EVP_MD_CTX, 
decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
 
  549    if (!EVP_MD_CTX_init(ctx.get())) {
 
  550        qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Failed to initialize signature verification:" << ERR_error_string(ERR_get_error(), 
nullptr);
 
  554    EVP_PKEY_CTX *pctx = 
nullptr; 
 
  555    if (!EVP_DigestVerifyInit(ctx.get(), &pctx, md, 
nullptr, key)) {
 
  556        qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Failed to initialize signature verification:" << ERR_error_string(ERR_get_error(), 
nullptr);
 
  560    EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING);
 
  561    const auto result = EVP_DigestVerify(ctx.get(),
 
  562                                         reinterpret_cast<const unsigned char *
>(signature.
constData()),
 
  564                                         reinterpret_cast<const unsigned char *
>(message.constData()),
 
  568        qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Signature verification failed:" << ERR_error_string(ERR_get_error(), 
nullptr);
 
  572    qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Signature successfully verified";
 
  576static uint64_t getKeyE(EVP_PKEY *key)
 
  578    BIGNUM *bne = 
nullptr;
 
  579    EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &bne);
 
  580    const uint64_t size = BN_get_word(bne);
 
  585void DKIMCheckSignatureJob::verifyRSASignature()
 
  590    const auto publicKey = loadRSAPublicKey(mDkimKeyRecord.publicKey().toLatin1());
 
  592        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Failed to load public key";
 
  593        return verificationFailed(DKIMError::PublicKeyConversionError);
 
  595    qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Success loading public key";
 
  598    if (
const auto keyE = getKeyE(publicKey.get()); keyE * 4 < 1024) {
 
  599        const int publicRsaTooSmallPolicyValue = mPolicy.publicRsaTooSmallPolicy();
 
  600        if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Nothing) {
 
  602        } 
else if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Warning) {
 
  603            mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::PublicRsaKeyTooSmall;
 
  604        } 
else if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Error) {
 
  605            mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyTooSmall;
 
  606            mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  607            Q_EMIT result(createCheckResult());
 
  611    } 
else if (keyE * 4 < 2048) {
 
  616    const auto md = evpAlgo(mDkimInfo.hashingAlgorithm());
 
  618        return verificationFailed(DKIMError::InvalidBodyHashAlgorithm);
 
  622    if (
const auto result = doVerifySignature(publicKey.get(), md, signature, mHeaderCanonizationResult.toLatin1()); !result.has_value()) {
 
  624        return verificationFailed(DKIMError::ImpossibleToVerifySignature);
 
  625    } 
else if (!result.value()) {
 
  627        computeHeaderCanonization(
false);
 
  628        if (
const auto result = doVerifySignature(publicKey.get(), md, signature, mHeaderCanonizationResult.toLatin1()); !result.has_value()) {
 
  630            return verificationFailed(DKIMError::ImpossibleToVerifySignature);
 
  631        } 
else if (!result.value()) {
 
  632            qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Signature verification failed";
 
  633            return verificationFailed(DKIMError::ImpossibleToVerifySignature);
 
  637    mStatus = DKIMStatus::Valid;
 
  638    Q_EMIT result(createCheckResult());
 
  642void DKIMCheckSignatureJob::verificationFailed(DKIMError error)
 
  645    mStatus = DKIMStatus::Invalid;
 
  646    Q_EMIT result(createCheckResult());
 
  660DKIMCheckSignatureJob::DKIMWarning DKIMCheckSignatureJob::warning()
 const 
  665void DKIMCheckSignatureJob::setWarning(DKIMCheckSignatureJob::DKIMWarning warning)
 
  680MessageViewer::DKIMCheckSignatureJob::DKIMStatus DKIMCheckSignatureJob::checkSignature(
const DKIMInfo &info)
 
  683    if (info.expireTime() != -1 && info.expireTime() < currentDate) {
 
  684        mWarning = DKIMCheckSignatureJob::DKIMWarning::SignatureExpired;
 
  686    if (info.signatureTimeStamp() != -1 && info.signatureTimeStamp() > currentDate) {
 
  687        mWarning = DKIMCheckSignatureJob::DKIMWarning::SignatureCreatedInFuture;
 
  689    if (info.signature().
isEmpty()) {
 
  690        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Signature doesn't exist";
 
  691        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingSignature;
 
  692        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  695        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"From is not include in headers list";
 
  696        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingFrom;
 
  697        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  700        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Domain is not defined.";
 
  701        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainNotExist;
 
  702        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  704    if (info.query() != QLatin1StringView(
"dns/txt")) {
 
  705        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"Query is incorrect: " << info.query();
 
  706        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidQueryMethod;
 
  707        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  710    if ((info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Any)
 
  711        || (info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Unknown)) {
 
  712        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"body header algorithm is empty";
 
  713        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyHashAlgorithm;
 
  714        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  716    if (info.signingAlgorithm().
isEmpty()) {
 
  717        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"signature algorithm is empty";
 
  718        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidSignAlgorithm;
 
  719        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  722    if (info.hashingAlgorithm() == DKIMInfo::HashingAlgorithmType::Sha1) {
 
  723        if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Nothing) {
 
  725        } 
else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Warning) {
 
  726            qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"hash algorithm is not secure sha1 : Error";
 
  727            mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::HashAlgorithmUnsafe;
 
  728        } 
else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Error) {
 
  729            qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"hash algorithm is not secure sha1: Error";
 
  730            mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::HashAlgorithmUnsafeSha1;
 
  731            return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  736    if (!info.agentOrUserIdentifier().
endsWith(info.iDomain())) {
 
  737        qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << 
"AUID is not in a subdomain of SDID";
 
  738        mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::IDomainError;
 
  739        return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
 
  743    return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid;
 
  746DKIMCheckSignatureJob::DKIMError DKIMCheckSignatureJob::error()
 const 
  751DKIMCheckSignatureJob::DKIMStatus DKIMCheckSignatureJob::status()
 const 
  756void DKIMCheckSignatureJob::setStatus(DKIMCheckSignatureJob::DKIMStatus 
status)
 
  761QString DKIMCheckSignatureJob::dkimValue()
 const 
  766bool DKIMCheckSignatureJob::CheckSignatureResult::isValid()
 const 
  768    return status != DKIMCheckSignatureJob::DKIMStatus::Unknown;
 
  771bool DKIMCheckSignatureJob::CheckSignatureResult::operator==(
const DKIMCheckSignatureJob::CheckSignatureResult &other)
 const 
  773    return error == other.error && warning == other.warning && status == other.status && fromEmail == other.fromEmail && auid == other.auid
 
  774        && sdid == other.sdid && listSignatureAuthenticationResult == other.listSignatureAuthenticationResult;
 
  777bool DKIMCheckSignatureJob::CheckSignatureResult::operator!=(
const DKIMCheckSignatureJob::CheckSignatureResult &other)
 const 
  779    return !CheckSignatureResult::operator==(other);
 
  782QDebug 
operator<<(QDebug d, 
const DKIMCheckSignatureJob::CheckSignatureResult &t)
 
  784    d << 
" error " << t.error;
 
  785    d << 
" warning " << t.warning;
 
  786    d << 
" status " << t.status;
 
  787    d << 
" signedBy " << t.sdid;
 
  788    d << 
" fromEmail " << t.fromEmail;
 
  789    d << 
" auid " << t.auid;
 
  790    d << 
" authenticationResult " << t.listSignatureAuthenticationResult;
 
  794QDebug 
operator<<(QDebug d, 
const DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult &t)
 
  796    d << 
" method " << t.method;
 
  797    d << 
" errorStr " << t.errorStr;
 
  798    d << 
" status " << t.status;
 
  799    d << 
" sdid " << t.sdid;
 
  800    d << 
" auid " << t.auid;
 
  801    d << 
" inforesult " << t.infoResult;
 
  805bool DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult::operator==(
const DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult &other)
 const 
  807    return errorStr == other.errorStr && method == other.method && status == other.status && sdid == other.sdid && auid == other.auid
 
  808        && infoResult == other.infoResult;
 
  811bool DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult::isValid()
 const 
  814    return (method != AuthenticationMethod::Unknown);
 
  817#include "moc_dkimchecksignaturejob.cpp" 
QSharedPointer< Message > Ptr
 
The DKIMCheckPolicy class.
 
Q_SCRIPTABLE CaptureState status()
 
OKULARCORE_EXPORT QString errorString(SigningResult result, const QVariant &additionalMessage)
 
QDebug operator<<(QDebug dbg, const PerceptualColor::MultiSpinBoxSection &value)
 
const char * constData() const const
 
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
 
qsizetype size() const const
 
qint64 currentSecsSinceEpoch()
 
const_reference at(qsizetype i) const const
 
qsizetype count() const const
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
 
QString fromLatin1(QByteArrayView str)
 
QString fromLocal8Bit(QByteArrayView str)
 
bool isEmpty() const const
 
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const