Messagelib

dkiminfo.cpp
1 /*
2  SPDX-FileCopyrightText: 2018-2023 Laurent Montel <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "dkiminfo.h"
8 #include "dkimutil.h"
9 #include "messageviewer_dkimcheckerdebug.h"
10 
11 using namespace MessageViewer;
12 
13 DKIMInfo::DKIMInfo() = default;
14 
15 bool DKIMInfo::parseDKIM(const QString &header)
16 {
17  if (header.isEmpty()) {
18  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Error: trying to parse empty header";
19  return false;
20  }
21  QString newHeaders = header;
22  newHeaders.replace(QLatin1String("; "), QLatin1String(";"));
23  const QStringList items = newHeaders.split(QLatin1Char(';'), Qt::SkipEmptyParts);
24  bool foundCanonizations = false;
25  for (int i = 0; i < items.count(); ++i) {
26  const QString elem = items.at(i).trimmed();
27  if (elem.startsWith(QLatin1String("v="))) {
28 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
29  mVersion = elem.rightRef(elem.length() - 2).toInt();
30 #else
31  mVersion = QStringView(elem).right(elem.length() - 2).toInt();
32 #endif
33  if (mVersion != 1) {
34  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Version is not correct " << mVersion;
35  }
36  } else if (elem.startsWith(QLatin1String("a="))) {
37  // Parse it as "algorithm.signature-algorithm.hash
38  parseAlgorithm(elem.right(elem.length() - 2));
39  } else if (elem.startsWith(QLatin1String("t="))) {
40  mSignatureTimeStamp = elem.right(elem.length() - 2).toLong();
41  } else if (elem.startsWith(QLatin1String("c="))) {
42  // Parse header/body canonicalization (example c=relaxed/simple) only relaxed and simple.
43  parseCanonicalization(elem.right(elem.length() - 2));
44  foundCanonizations = true;
45  } else if (elem.startsWith(QLatin1String("bh="))) {
46  mBodyHash = elem.right(elem.length() - 3).remove(QLatin1Char(' '));
47  } else if (elem.startsWith(QLatin1String("l="))) {
48 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
49  mBodyLengthCount = elem.rightRef(elem.length() - 2).toInt();
50 #else
51  mBodyLengthCount = QStringView(elem).right(elem.length() - 2).toInt();
52 #endif
53  } else if (elem.startsWith(QLatin1String("i="))) {
54  mAgentOrUserIdentifier = elem.right(elem.length() - 2);
55  } else if (elem.startsWith(QLatin1String("q="))) {
56  mQuery = elem.right(elem.length() - 2);
57  if (mQuery != QLatin1String("dns/txt")) {
58  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Query is not correct and not supported " << mQuery;
59  }
60  } else if (elem.startsWith(QLatin1String("d="))) {
61  mDomain = elem.right(elem.length() - 2).trimmed();
62  } else if (elem.startsWith(QLatin1String("s="))) {
63  mSelector = elem.right(elem.length() - 2).trimmed();
64  } else if (elem.startsWith(QLatin1String("b="))) {
65  mSignature = elem.right(elem.length() - 2);
66  } else if (elem.startsWith(QLatin1String("h="))) {
67  const QString str = MessageViewer::DKIMUtil::cleanString(elem.right(elem.length() - 2));
68  mListSignedHeader = str.split(QLatin1Char(':'));
69  } else if (elem.startsWith(QLatin1String("x="))) {
70  mExpireTime = elem.right(elem.length() - 2).toLong();
71  } else if (elem.startsWith(QLatin1String("z="))) {
72  mCopiedHeaderField = elem.right(elem.length() - 2).split(QLatin1Char(':'));
73  } else {
74  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Unknown element type" << elem << " : items : " << items;
75  }
76  }
77  if (!foundCanonizations) { // Default
78  mHeaderCanonization = Simple;
79  mBodyCanonization = Simple;
80  }
81  if (mVersion == -1) {
82  mVersion = 1;
83  }
84  if (mQuery.isEmpty()) {
85  mQuery = QStringLiteral("dns/txt");
86  }
87  if (mAgentOrUserIdentifier.isEmpty()) {
88  mAgentOrUserIdentifier = QLatin1Char('@') + mDomain;
89  mIDomain = mDomain;
90  } else {
91  const QStringList lst = mAgentOrUserIdentifier.split(QLatin1Char('@'));
92  if (lst.count() == 2) {
93  if (mAgentOrUserIdentifier.isEmpty()) {
94  mAgentOrUserIdentifier = QLatin1Char('@') + mDomain;
95  }
96  mIDomain = lst.at(1);
97  }
98  }
99  return true;
100 }
101 
102 void DKIMInfo::parseAlgorithm(const QString &str)
103 {
104  // currently only "rsa-sha1" or "rsa-sha256"
105  const QStringList lst = str.split(QLatin1Char('-'));
106  if (lst.count() != 2) {
107  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "algorithm is invalid " << str;
108  // Error
109  } else {
110  mSigningAlgorithm = lst.at(0);
111  const QString hashStr = lst.at(1);
112  if (hashStr == QLatin1String("sha1")) {
113  mHashingAlgorithm = HashingAlgorithmType::Sha1;
114  } else if (hashStr == QLatin1String("sha256")) {
115  mHashingAlgorithm = HashingAlgorithmType::Sha256;
116  } else {
117  mHashingAlgorithm = HashingAlgorithmType::Unknown;
118  }
119  }
120 }
121 
122 QString DKIMInfo::iDomain() const
123 {
124  return mIDomain;
125 }
126 
127 void DKIMInfo::setIDomain(const QString &iDomain)
128 {
129  mIDomain = iDomain;
130 }
131 
132 void DKIMInfo::parseCanonicalization(const QString &str)
133 {
134  if (!str.isEmpty()) {
135  const QStringList canonicalization = str.split(QLatin1Char('/'));
136  // qDebug() << " canonicalization "<< canonicalization;
137  if (canonicalization.count() >= 1) {
138  if (canonicalization.at(0) == QLatin1String("relaxed")) {
139  mHeaderCanonization = DKIMInfo::Relaxed;
140  } else if (canonicalization.at(0) == QLatin1String("simple")) {
141  mHeaderCanonization = DKIMInfo::Simple;
142  } else {
143  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "canonicalization for header unknown " << canonicalization.at(0);
144  mHeaderCanonization = DKIMInfo::Unknown;
145  return;
146  }
147  if (canonicalization.count() == 1) {
148  mBodyCanonization = DKIMInfo::Simple;
149  } else if (canonicalization.count() == 2) {
150  if (canonicalization.at(1) == QLatin1String("relaxed")) {
151  mBodyCanonization = DKIMInfo::Relaxed;
152  } else if (canonicalization.at(1) == QLatin1String("simple")) {
153  mBodyCanonization = DKIMInfo::Simple;
154  } else {
155  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "canonicalization for body unknown " << canonicalization.at(1);
156  mBodyCanonization = DKIMInfo::Unknown;
157  return;
158  }
159  } else {
160  qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Problem during parsing canonicalization " << str;
161  mHeaderCanonization = DKIMInfo::Unknown;
162  mBodyCanonization = DKIMInfo::Unknown;
163  }
164  }
165  }
166 }
167 
168 QStringList DKIMInfo::copiedHeaderField() const
169 {
170  return mCopiedHeaderField;
171 }
172 
173 void DKIMInfo::setCopiedHeaderField(const QStringList &copiedHeaderField)
174 {
175  mCopiedHeaderField = copiedHeaderField;
176 }
177 
178 DKIMInfo::CanonicalizationType DKIMInfo::bodyCanonization() const
179 {
180  return mBodyCanonization;
181 }
182 
183 void DKIMInfo::setBodyCanonization(CanonicalizationType bodyCanonization)
184 {
185  mBodyCanonization = bodyCanonization;
186 }
187 
188 bool DKIMInfo::operator==(const DKIMInfo &other) const
189 {
190  return mVersion == other.version() && mHashingAlgorithm == other.hashingAlgorithm() && mSigningAlgorithm == other.signingAlgorithm()
191  && mDomain == other.domain() && mSelector == other.selector() && mBodyHash == other.bodyHash() && mSignatureTimeStamp == other.signatureTimeStamp()
192  && mExpireTime == other.expireTime() && mQuery == other.query() && mSignature == other.signature()
193  && mAgentOrUserIdentifier == other.agentOrUserIdentifier() && mBodyLengthCount == other.bodyLengthCount()
194  && mListSignedHeader == other.listSignedHeader() && mHeaderCanonization == other.headerCanonization() && mBodyCanonization == other.bodyCanonization()
195  && mIDomain == other.iDomain();
196 }
197 
198 DKIMInfo::CanonicalizationType DKIMInfo::headerCanonization() const
199 {
200  return mHeaderCanonization;
201 }
202 
203 void DKIMInfo::setHeaderCanonization(CanonicalizationType headerCanonization)
204 {
205  mHeaderCanonization = headerCanonization;
206 }
207 
208 int DKIMInfo::version() const
209 {
210  return mVersion;
211 }
212 
213 void DKIMInfo::setVersion(int version)
214 {
215  mVersion = version;
216 }
217 
218 DKIMInfo::HashingAlgorithmType DKIMInfo::hashingAlgorithm() const
219 {
220  return mHashingAlgorithm;
221 }
222 
223 void DKIMInfo::setHashingAlgorithm(DKIMInfo::HashingAlgorithmType hashingAlgorithm)
224 {
225  mHashingAlgorithm = hashingAlgorithm;
226 }
227 
228 QString DKIMInfo::domain() const
229 {
230  return mDomain;
231 }
232 
233 void DKIMInfo::setDomain(const QString &domain)
234 {
235  mDomain = domain;
236 }
237 
238 QString DKIMInfo::selector() const
239 {
240  return mSelector;
241 }
242 
243 void DKIMInfo::setSelector(const QString &selector)
244 {
245  mSelector = selector;
246 }
247 
248 QString DKIMInfo::bodyHash() const
249 {
250  return mBodyHash;
251 }
252 
253 void DKIMInfo::setBodyHash(const QString &bodyHash)
254 {
255  mBodyHash = bodyHash;
256 }
257 
258 bool DKIMInfo::isValid() const
259 {
260  if (mBodyCanonization == DKIMInfo::Unknown || mHeaderCanonization == DKIMInfo::Unknown) {
261  return false;
262  }
263 
264  return !mSelector.isEmpty() && !mDomain.isEmpty() && !mBodyHash.isEmpty()
265  && ((mHashingAlgorithm == HashingAlgorithmType::Sha1) || mHashingAlgorithm == HashingAlgorithmType::Sha256);
266 }
267 
268 QStringList DKIMInfo::listSignedHeader() const
269 {
270  return mListSignedHeader;
271 }
272 
273 void DKIMInfo::setListSignedHeader(const QStringList &listSignedHeader)
274 {
275  mListSignedHeader = listSignedHeader;
276 }
277 
278 QString DKIMInfo::signingAlgorithm() const
279 {
280  return mSigningAlgorithm;
281 }
282 
283 void DKIMInfo::setSigningAlgorithm(const QString &signingAlgorithm)
284 {
285  mSigningAlgorithm = signingAlgorithm;
286 }
287 
288 qint64 DKIMInfo::signatureTimeStamp() const
289 {
290  return mSignatureTimeStamp;
291 }
292 
293 void DKIMInfo::setSignatureTimeStamp(qint64 signatureTimeStamp)
294 {
295  mSignatureTimeStamp = signatureTimeStamp;
296 }
297 
298 QString DKIMInfo::query() const
299 {
300  return mQuery;
301 }
302 
303 void DKIMInfo::setQuery(const QString &query)
304 {
305  mQuery = query;
306 }
307 
308 qint64 DKIMInfo::expireTime() const
309 {
310  return mExpireTime;
311 }
312 
313 void DKIMInfo::setExpireTime(qint64 expireTime)
314 {
315  mExpireTime = expireTime;
316 }
317 
318 QString DKIMInfo::signature() const
319 {
320  return mSignature;
321 }
322 
323 void DKIMInfo::setSignature(const QString &signature)
324 {
325  mSignature = signature;
326 }
327 
328 QString DKIMInfo::agentOrUserIdentifier() const
329 {
330  return mAgentOrUserIdentifier;
331 }
332 
333 void DKIMInfo::setAgentOrUserIdentifier(const QString &userAgent)
334 {
335  mAgentOrUserIdentifier = userAgent;
336 }
337 
338 int DKIMInfo::bodyLengthCount() const
339 {
340  return mBodyLengthCount;
341 }
342 
343 void DKIMInfo::setBodyLengthCount(int bodyLengthCount)
344 {
345  mBodyLengthCount = bodyLengthCount;
346 }
347 
348 QDebug operator<<(QDebug d, const DKIMInfo &t)
349 {
350  d << "mVersion " << t.version();
351  d << "mHashingAlgorithm " << t.hashingAlgorithm();
352  d << "mSigningAlgorithm " << t.signingAlgorithm();
353  d << "mDomain " << t.domain();
354  d << "mSelector " << t.selector();
355  d << "mBodyHash " << t.bodyHash();
356  d << "mSignatureTimeStamp " << t.signatureTimeStamp();
357  d << "mExpireTime " << t.expireTime();
358  d << "mQuery " << t.query();
359  d << "mSignature " << t.signature();
360  d << "mAgentOrUserIdentifier " << t.agentOrUserIdentifier();
361  d << "mBodyLengthCount " << t.bodyLengthCount();
362  d << "mListSignedHeader " << t.listSignedHeader();
363  d << "mHeaderCanonization " << t.headerCanonization();
364  d << "mBodyCanonization " << t.bodyCanonization();
365  d << "mIdomain " << t.iDomain();
366  return d;
367 }
int toInt(bool *ok, int base) const const
QStringView right(qsizetype length) const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int count(const T &value) const const
QString trimmed() const const
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
SkipEmptyParts
bool isEmpty() const const
int length() const const
const T & at(int i) const const
QString & replace(int position, int n, QChar after)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
unsigned int version()
QString right(int n) const const
The DKIMInfo class.
Definition: dkiminfo.h:19
QStringRef rightRef(int n) const const
long toLong(bool *ok, int base) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Mar 26 2023 04:08:11 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.