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>
24using namespace MessageViewer;
25DKIMCheckSignatureJob::DKIMCheckSignatureJob(
QObject *parent)
30DKIMCheckSignatureJob::~DKIMCheckSignatureJob() =
default;
32MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult DKIMCheckSignatureJob::createCheckResult()
const
34 MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult result;
35 result.error = mError;
36 result.warning = mWarning;
37 result.status = mStatus;
38 result.sdid = mDkimInfo.domain();
39 result.auid = mDkimInfo.agentOrUserIdentifier();
40 result.fromEmail = mFromEmail;
41 result.listSignatureAuthenticationResult = mCheckSignatureAuthenticationResult;
45QString DKIMCheckSignatureJob::bodyCanonizationResult()
const
47 return mBodyCanonizationResult;
50QString DKIMCheckSignatureJob::headerCanonizationResult()
const
52 return mHeaderCanonizationResult;
55void DKIMCheckSignatureJob::start()
58 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Item has not a message";
59 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
60 Q_EMIT result(createCheckResult());
64 if (
auto hrd = mMessage->headerByType(
"DKIM-Signature")) {
65 mDkimValue = hrd->asUnicodeString();
68 if (
auto hrd = mMessage->from(
false)) {
72 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::EmailNotSigned;
73 Q_EMIT result(createCheckResult());
77 qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"mFromEmail " << mFromEmail;
78 if (!mDkimInfo.parseDKIM(mDkimValue)) {
79 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Impossible to parse header" << mDkimValue;
80 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
81 Q_EMIT result(createCheckResult());
86 const MessageViewer::DKIMCheckSignatureJob::DKIMStatus status = checkSignature(mDkimInfo);
87 if (status != MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid) {
89 Q_EMIT result(createCheckResult());
94 switch (mDkimInfo.bodyCanonization()) {
95 case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
96 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyCanonicalization;
97 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
98 Q_EMIT result(createCheckResult());
101 case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
102 mBodyCanonizationResult = bodyCanonizationSimple();
104 case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
105 mBodyCanonizationResult = bodyCanonizationRelaxed();
110 if (mDkimInfo.bodyLengthCount() != -1) {
111 if (mDkimInfo.bodyLengthCount() > mBodyCanonizationResult.
length()) {
113 qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
" mDkimInfo.bodyLengthCount() " << mDkimInfo.bodyLengthCount() <<
" mBodyCanonizationResult.length() "
114 << mBodyCanonizationResult.
length();
115 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::SignatureTooLarge;
116 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
117 Q_EMIT result(createCheckResult());
120 }
else if (mDkimInfo.bodyLengthCount() < mBodyCanonizationResult.
length()) {
121 mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::SignatureTooSmall;
124 mBodyCanonizationResult = mBodyCanonizationResult.
left(mDkimInfo.bodyLengthCount());
127 mBodyCanonizationResult = mBodyCanonizationResult.
right(mBodyCanonizationResult.
length() - 2);
131 mBodyCanonizationResult.
replace(QStringLiteral(
" This is a multi-part message in MIME format"),
132 QStringLiteral(
"This is a multi-part message in MIME format"));
136 mBodyCanonizationResult.
replace(QStringLiteral(
" This is a cryptographically signed message in MIME format."),
137 QStringLiteral(
"This is a cryptographically signed message in MIME format."));
141 mBodyCanonizationResult.
remove(reg);
143#ifdef DEBUG_SIGNATURE_DKIM
144 QFile caFile(QStringLiteral(
"/tmp/bodycanon-kmail.txt"));
147 outStream << mBodyCanonizationResult;
152 switch (mDkimInfo.hashingAlgorithm()) {
153 case DKIMInfo::HashingAlgorithmType::Sha1:
156 case DKIMInfo::HashingAlgorithmType::Sha256:
159 case DKIMInfo::HashingAlgorithmType::Any:
160 case DKIMInfo::HashingAlgorithmType::Unknown:
161 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InsupportedHashAlgorithm;
162 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
163 Q_EMIT result(createCheckResult());
169 qDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"resultHash " << resultHash <<
"mDkimInfo.bodyHash()" << mDkimInfo.bodyHash();
170 if (resultHash != mDkimInfo.bodyHash().
toLatin1()) {
171 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
" Corrupted body hash";
172 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::CorruptedBodyHash;
173 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
174 Q_EMIT result(createCheckResult());
179 if (mDkimInfo.headerCanonization() == MessageViewer::DKIMInfo::CanonicalizationType::Unknown) {
180 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidHeaderCanonicalization;
181 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
182 Q_EMIT result(createCheckResult());
187 if (!mHeaderParser.wasAlreadyParsed()) {
188 mHeaderParser.setHead(mMessage->head());
189 mHeaderParser.parse();
192 computeHeaderCanonization(
true);
193 if (mPolicy.saveKey() == MessageViewer::MessageViewerSettings::EnumSaveKey::Save) {
194 const QString keyValue = MessageViewer::DKIMManagerKey::self()->keyValue(mDkimInfo.selector(), mDkimInfo.domain());
197 downloadKey(mDkimInfo);
199 parseDKIMKeyRecord(keyValue, mDkimInfo.domain(), mDkimInfo.selector(),
false);
200 MessageViewer::DKIMManagerKey::self()->updateLastUsed(mDkimInfo.domain(), mDkimInfo.selector());
203 downloadKey(mDkimInfo);
207void DKIMCheckSignatureJob::computeHeaderCanonization(
bool removeQuoteOnContentType)
210 switch (mDkimInfo.headerCanonization()) {
211 case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
213 case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
214 mHeaderCanonizationResult = headerCanonizationSimple();
216 case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
217 mHeaderCanonizationResult = headerCanonizationRelaxed(removeQuoteOnContentType);
240 QString dkimValue = mDkimValue;
242 switch (mDkimInfo.headerCanonization()) {
243 case MessageViewer::DKIMInfo::CanonicalizationType::Unknown:
245 case MessageViewer::DKIMInfo::CanonicalizationType::Simple:
246 mHeaderCanonizationResult +=
QLatin1StringView(
"\r\n") + MessageViewer::DKIMUtil::headerCanonizationSimple(QStringLiteral(
"dkim-signature"), dkimValue);
248 case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed:
250 + MessageViewer::DKIMUtil::headerCanonizationRelaxed(QStringLiteral(
"dkim-signature"), dkimValue, removeQuoteOnContentType);
253#ifdef DEBUG_SIGNATURE_DKIM
258 outHeaderStream << mHeaderCanonizationResult;
263void DKIMCheckSignatureJob::setHeaderParser(
const DKIMHeaderParser &headerParser)
265 mHeaderParser = headerParser;
270 mCheckSignatureAuthenticationResult = lst;
273QString DKIMCheckSignatureJob::bodyCanonizationSimple()
const
290 return MessageViewer::DKIMUtil::bodyCanonizationSimple(
QString::fromLatin1(mMessage->encodedBody()));
293QString DKIMCheckSignatureJob::bodyCanonizationRelaxed()
const
318QString DKIMCheckSignatureJob::headerCanonizationSimple()
const
324 const auto listSignedHeader{mDkimInfo.listSignedHeader()};
325 for (
const QString &header : listSignedHeader) {
326 const QString str = parser.headerType(header.toLower());
331 headers += MessageViewer::DKIMUtil::headerCanonizationSimple(header, str);
337QString DKIMCheckSignatureJob::headerCanonizationRelaxed(
bool removeQuoteOnContentType)
const
364 const auto listSignedHeader = mDkimInfo.listSignedHeader();
365 for (
const QString &header : listSignedHeader) {
366 const QString str = parser.headerType(header.toLower());
371 headers += MessageViewer::DKIMUtil::headerCanonizationRelaxed(header, str, removeQuoteOnContentType);
377void DKIMCheckSignatureJob::downloadKey(
const DKIMInfo &info)
380 job->setDomainName(info.domain());
381 job->setSelectorName(info.selector());
382 connect(job, &DKIMDownloadKeyJob::error,
this, [
this](
const QString &errorString) {
383 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Impossible to start downloadkey: error returned: " << errorString;
384 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey;
385 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
386 Q_EMIT result(createCheckResult());
389 connect(job, &DKIMDownloadKeyJob::success,
this, &DKIMCheckSignatureJob::slotDownloadKeyDone);
392 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Impossible to start downloadkey";
393 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey;
394 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
395 Q_EMIT result(createCheckResult());
403 if (lst.
count() != 1) {
414void DKIMCheckSignatureJob::parseDKIMKeyRecord(
const QString &str,
const QString &domain,
const QString &selector,
bool storeKeyValue)
416 qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG)
417 <<
"void DKIMCheckSignatureJob::parseDKIMKeyRecord(const QString &str, const QString &domain, const QString &selector, bool storeKeyValue) key:" << str;
418 if (!mDkimKeyRecord.parseKey(str)) {
419 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Impossible to parse key record " << str;
420 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
421 Q_EMIT result(createCheckResult());
425 const QString keyType{mDkimKeyRecord.keyType()};
427 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"mDkimKeyRecord key type is unknown " << keyType <<
" str " << str;
428 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
429 Q_EMIT result(createCheckResult());
442 if (mDkimInfo.iDomain() != mDkimInfo.domain()) {
443 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
444 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainI;
445 Q_EMIT result(createCheckResult());
454 if (!mPolicy.verifySignatureWhenOnlyTest()) {
455 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Testing mode!";
456 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::TestKeyMode;
457 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
458 Q_EMIT result(createCheckResult());
463 if (mDkimKeyRecord.publicKey().
isEmpty()) {
465 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"mDkimKeyRecord public key is empty. It was revoked ";
466 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyWasRevoked;
467 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
468 Q_EMIT result(createCheckResult());
474 Q_EMIT storeKey(str, domain, selector);
480void DKIMCheckSignatureJob::verifySignature()
482 const QString keyType{mDkimKeyRecord.keyType()};
484 verifyRSASignature();
486 verifyEd25519Signature();
488 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
" It's a bug " << keyType;
492void DKIMCheckSignatureJob::verifyEd25519Signature()
495 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"it's a Ed25519 signed email";
496 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyConversionError;
497 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
498 Q_EMIT result(createCheckResult());
502void DKIMCheckSignatureJob::verifyRSASignature()
509 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Public key read failed" << conversionResult <<
" public key" << mDkimKeyRecord.publicKey();
510 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyConversionError;
511 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
512 Q_EMIT result(createCheckResult());
516 qDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Success loading public key";
523 const int publicRsaTooSmallPolicyValue = mPolicy.publicRsaTooSmallPolicy();
524 if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Nothing) {
526 }
else if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Warning) {
527 mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::PublicRsaKeyTooSmall;
528 }
else if (publicRsaTooSmallPolicyValue == MessageViewer::MessageViewerSettings::EnumPublicRsaTooSmall::Error) {
529 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyTooSmall;
530 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
531 Q_EMIT result(createCheckResult());
546 switch (mDkimInfo.hashingAlgorithm()) {
547 case DKIMInfo::HashingAlgorithmType::Sha1:
550 case DKIMInfo::HashingAlgorithmType::Sha256:
553 case DKIMInfo::HashingAlgorithmType::Any:
554 case DKIMInfo::HashingAlgorithmType::Unknown: {
556 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToVerifySignature;
557 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
558 Q_EMIT result(createCheckResult());
560 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"DKIMInfo::HashingAlgorithmType undefined ! ";
565 computeHeaderCanonization(
false);
566 const QCA::SecureArray secWithoutQuote = mHeaderCanonizationResult.toLatin1();
568 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Signature invalid";
570 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToVerifySignature;
571 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
572 Q_EMIT result(createCheckResult());
578 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Impossible to verify signature";
579 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToVerifySignature;
580 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
581 Q_EMIT result(createCheckResult());
585 mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid;
586 Q_EMIT result(createCheckResult());
600DKIMCheckSignatureJob::DKIMWarning DKIMCheckSignatureJob::warning()
const
605void DKIMCheckSignatureJob::setWarning(DKIMCheckSignatureJob::DKIMWarning warning)
620MessageViewer::DKIMCheckSignatureJob::DKIMStatus DKIMCheckSignatureJob::checkSignature(
const DKIMInfo &info)
623 if (info.expireTime() != -1 && info.expireTime() < currentDate) {
624 mWarning = DKIMCheckSignatureJob::DKIMWarning::SignatureExpired;
626 if (info.signatureTimeStamp() != -1 && info.signatureTimeStamp() > currentDate) {
627 mWarning = DKIMCheckSignatureJob::DKIMWarning::SignatureCreatedInFuture;
629 if (info.signature().
isEmpty()) {
630 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Signature doesn't exist";
631 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingSignature;
632 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
635 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"From is not include in headers list";
636 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingFrom;
637 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
640 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Domain is not defined.";
641 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainNotExist;
642 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
645 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"Query is incorrect: " << info.query();
646 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidQueryMethod;
647 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
650 if ((info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Any)
651 || (info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Unknown)) {
652 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"body header algorithm is empty";
653 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyHashAlgorithm;
654 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
656 if (info.signingAlgorithm().
isEmpty()) {
657 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"signature algorithm is empty";
658 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidSignAlgorithm;
659 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
662 if (info.hashingAlgorithm() == DKIMInfo::HashingAlgorithmType::Sha1) {
663 if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Nothing) {
665 }
else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Warning) {
666 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"hash algorithm is not secure sha1 : Error";
667 mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::HashAlgorithmUnsafe;
668 }
else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Error) {
669 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"hash algorithm is not secure sha1: Error";
670 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::HashAlgorithmUnsafeSha1;
671 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
676 if (!info.agentOrUserIdentifier().
endsWith(info.iDomain())) {
677 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) <<
"AUID is not in a subdomain of SDID";
678 mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::IDomainError;
679 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid;
683 return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid;
686DKIMCheckSignatureJob::DKIMError DKIMCheckSignatureJob::error()
const
691DKIMCheckSignatureJob::DKIMStatus DKIMCheckSignatureJob::status()
const
696void DKIMCheckSignatureJob::setStatus(DKIMCheckSignatureJob::DKIMStatus
status)
701QString DKIMCheckSignatureJob::dkimValue()
const
706bool DKIMCheckSignatureJob::CheckSignatureResult::isValid()
const
708 return status != DKIMCheckSignatureJob::DKIMStatus::Unknown;
711bool DKIMCheckSignatureJob::CheckSignatureResult::operator==(
const DKIMCheckSignatureJob::CheckSignatureResult &other)
const
713 return error == other.error && warning == other.warning &&
status == other.status && fromEmail == other.fromEmail && auid == other.auid
714 && sdid == other.sdid && listSignatureAuthenticationResult == other.listSignatureAuthenticationResult;
717bool DKIMCheckSignatureJob::CheckSignatureResult::operator!=(
const DKIMCheckSignatureJob::CheckSignatureResult &other)
const
719 return !CheckSignatureResult::operator==(other);
724 d <<
" error " << t.error;
725 d <<
" warning " << t.warning;
726 d <<
" status " << t.status;
727 d <<
" signedBy " << t.sdid;
728 d <<
" fromEmail " << t.fromEmail;
729 d <<
" auid " << t.auid;
730 d <<
" authenticationResult " << t.listSignatureAuthenticationResult;
736 d <<
" method " << t.method;
737 d <<
" errorStr " << t.errorStr;
738 d <<
" status " << t.status;
739 d <<
" sdid " << t.sdid;
740 d <<
" auid " << t.auid;
741 d <<
" inforesult " << t.infoResult;
745bool DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult::operator==(
const DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult &other)
const
747 return errorStr == other.errorStr && method == other.method &&
status == other.status && sdid == other.sdid && auid == other.auid
748 && infoResult == other.infoResult;
751bool DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult::isValid()
const
754 return (method != AuthenticationMethod::Unknown);
757#include "moc_dkimchecksignaturejob.cpp"
The DKIMCheckPolicy class.
The DKIMDownloadKeyJob class.
RSAPublicKey toRSA() const
bool verifyMessage(const MemoryRegion &a, const QByteArray &sig, SignatureAlgorithm alg, SignatureFormat format=DefaultFormat)
static PublicKey fromDER(const QByteArray &a, ConvertResult *result=nullptr, const QString &provider=QString())
Q_SCRIPTABLE CaptureState status()
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
QCA_EXPORT QByteArray base64ToArray(const QString &base64String)
qint64 currentSecsSinceEpoch()
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
virtual void close() override
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)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
long toLong(bool *ok, int base) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const