Messagelib

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

KDE's Doxygen guidelines are available online.