diff options
-rw-r--r-- | framework/src/domain/mime/mailcrypto.cpp | 95 | ||||
-rw-r--r-- | framework/src/domain/mime/mailcrypto.h | 10 | ||||
-rw-r--r-- | framework/src/domain/mime/mailtemplates.cpp | 7 |
3 files changed, 61 insertions, 51 deletions
diff --git a/framework/src/domain/mime/mailcrypto.cpp b/framework/src/domain/mime/mailcrypto.cpp index 83ce293a..4e20c84b 100644 --- a/framework/src/domain/mime/mailcrypto.cpp +++ b/framework/src/domain/mime/mailcrypto.cpp | |||
@@ -142,18 +142,19 @@ Expected<GpgME::Error, QByteArray> exportPublicKey(const GpgME::Key &key) | |||
142 | * | 142 | * |
143 | * Used by the `createSignedEmail` and `createEncryptedEmail` functions. | 143 | * Used by the `createSignedEmail` and `createEncryptedEmail` functions. |
144 | */ | 144 | */ |
145 | Expected<GpgME::Error, KMime::Content *> appendPublicKey(KMime::Content *msg, const GpgME::Key &key) | 145 | Expected<GpgME::Error, std::unique_ptr<KMime::Content>> |
146 | appendPublicKey(std::unique_ptr<KMime::Content> msg, const GpgME::Key &key) | ||
146 | { | 147 | { |
147 | const auto publicKeyExportResult = exportPublicKey(key); | 148 | const auto publicKeyExportResult = exportPublicKey(key); |
148 | 149 | ||
149 | if(!publicKeyExportResult) { | 150 | if (!publicKeyExportResult) { |
150 | // "Could not export public key" | 151 | // "Could not export public key" |
151 | return makeUnexpected(publicKeyExportResult.error()); | 152 | return makeUnexpected(publicKeyExportResult.error()); |
152 | } | 153 | } |
153 | 154 | ||
154 | const auto publicKeyData = publicKeyExportResult.value(); | 155 | const auto publicKeyData = publicKeyExportResult.value(); |
155 | 156 | ||
156 | auto result = new KMime::Content; | 157 | auto result = std::unique_ptr<KMime::Content>(new KMime::Content); |
157 | result->contentType()->setMimeType("multipart/mixed"); | 158 | result->contentType()->setMimeType("multipart/mixed"); |
158 | result->contentType()->setBoundary(KMime::multiPartBoundary()); | 159 | result->contentType()->setBoundary(KMime::multiPartBoundary()); |
159 | 160 | ||
@@ -166,13 +167,11 @@ Expected<GpgME::Error, KMime::Content *> appendPublicKey(KMime::Content *msg, co | |||
166 | } | 167 | } |
167 | 168 | ||
168 | msg->assemble(); | 169 | msg->assemble(); |
169 | qWarning() << "Msg:" << msg->encodedContent().constData(); | ||
170 | 170 | ||
171 | result->addContent(msg); | 171 | result->addContent(msg.release()); |
172 | result->addContent(keyAttachment); | 172 | result->addContent(keyAttachment); |
173 | 173 | ||
174 | result->assemble(); | 174 | result->assemble(); |
175 | qDebug() << "Final message:\n" << result->encodedContent().constData(); | ||
176 | 175 | ||
177 | return result; | 176 | return result; |
178 | } | 177 | } |
@@ -193,8 +192,8 @@ Expected<GpgME::Error, QByteArray> encrypt(const QByteArray &content, const std: | |||
193 | return resultData; | 192 | return resultData; |
194 | } | 193 | } |
195 | 194 | ||
196 | Expected<GpgME::Error, QByteArray> signAndEncrypt(const QByteArray &content, const std::vector<GpgME::Key> &signingKeys, | 195 | Expected<GpgME::Error, QByteArray> signAndEncrypt(const QByteArray &content, |
197 | const std::vector<GpgME::Key> &encryptionKeys) | 196 | const std::vector<GpgME::Key> &signingKeys, const std::vector<GpgME::Key> &encryptionKeys) |
198 | { | 197 | { |
199 | QByteArray resultData; | 198 | QByteArray resultData; |
200 | 199 | ||
@@ -216,7 +215,7 @@ Expected<GpgME::Error, QByteArray> signAndEncrypt(const QByteArray &content, con | |||
216 | } | 215 | } |
217 | 216 | ||
218 | /** | 217 | /** |
219 | * Create a message like this (according to RFC 3156 Section 4): | 218 | * Create a message part like this (according to RFC 3156 Section 4): |
220 | * | 219 | * |
221 | * - multipart/encrypted | 220 | * - multipart/encrypted |
222 | * - application/pgp-encrypted (version information) | 221 | * - application/pgp-encrypted (version information) |
@@ -227,9 +226,9 @@ Expected<GpgME::Error, QByteArray> signAndEncrypt(const QByteArray &content, con | |||
227 | * | 226 | * |
228 | * The encrypted data can be generated by the `encrypt` or `signAndEncrypt` functions. | 227 | * The encrypted data can be generated by the `encrypt` or `signAndEncrypt` functions. |
229 | */ | 228 | */ |
230 | KMime::Content *createEncryptedPart(QByteArray encryptedData) | 229 | std::unique_ptr<KMime::Content> createEncryptedPart(QByteArray encryptedData) |
231 | { | 230 | { |
232 | KMime::Content *result = new KMime::Content; | 231 | auto result = std::unique_ptr<KMime::Content>(new KMime::Content); |
233 | 232 | ||
234 | result->contentType()->setMimeType("multipart/encrypted"); | 233 | result->contentType()->setMimeType("multipart/encrypted"); |
235 | result->contentType()->setBoundary(KMime::multiPartBoundary()); | 234 | result->contentType()->setBoundary(KMime::multiPartBoundary()); |
@@ -276,7 +275,7 @@ KMime::Content *createEncryptedPart(QByteArray encryptedData) | |||
276 | * - `application/pgp-keys` (the public key as attachment, which is the first of the | 275 | * - `application/pgp-keys` (the public key as attachment, which is the first of the |
277 | * `signingKeys`) | 276 | * `signingKeys`) |
278 | */ | 277 | */ |
279 | Expected<GpgME::Error, KMime::Content *> | 278 | Expected<GpgME::Error, std::unique_ptr<KMime::Content>> |
280 | createEncryptedEmail(KMime::Content *content, const std::vector<GpgME::Key> &encryptionKeys, | 279 | createEncryptedEmail(KMime::Content *content, const std::vector<GpgME::Key> &encryptionKeys, |
281 | const GpgME::Key &attachedKey, const std::vector<GpgME::Key> &signingKeys = {}) | 280 | const GpgME::Key &attachedKey, const std::vector<GpgME::Key> &signingKeys = {}) |
282 | { | 281 | { |
@@ -290,21 +289,23 @@ createEncryptedEmail(KMime::Content *content, const std::vector<GpgME::Key> &enc | |||
290 | return makeUnexpected(encryptionResult.error()); | 289 | return makeUnexpected(encryptionResult.error()); |
291 | } | 290 | } |
292 | 291 | ||
293 | auto encryptedData = encryptionResult.value(); | 292 | auto encryptedPart = createEncryptedPart(encryptionResult.value()); |
294 | 293 | ||
295 | KMime::Content *encryptedPart = createEncryptedPart(encryptedData); | 294 | auto publicKeyAppendResult = appendPublicKey(std::move(encryptedPart), attachedKey); |
296 | 295 | ||
297 | auto publicKeyAppendResult = appendPublicKey(encryptedPart, attachedKey); | 296 | if(publicKeyAppendResult) { |
298 | 297 | publicKeyAppendResult.value()->assemble(); | |
299 | // TODO: this is ugly | ||
300 | if (!publicKeyAppendResult) { | ||
301 | delete encryptedPart; | ||
302 | } | 298 | } |
303 | 299 | ||
304 | return publicKeyAppendResult; | 300 | return publicKeyAppendResult; |
305 | } | 301 | } |
306 | 302 | ||
307 | Expected<GpgME::Error, QByteArray> sign(const QByteArray &content, const std::vector<GpgME::Key> &signingKeys) | 303 | /** |
304 | * Sign the given content and returns the signing data and the algorithm used | ||
305 | * for integrity check in the "pgp-<algorithm>" format. | ||
306 | */ | ||
307 | Expected<GpgME::Error, std::pair<QByteArray, QString>> | ||
308 | sign(const QByteArray &content, const std::vector<GpgME::Key> &signingKeys) | ||
308 | { | 309 | { |
309 | QByteArray resultData; | 310 | QByteArray resultData; |
310 | 311 | ||
@@ -317,11 +318,17 @@ Expected<GpgME::Error, QByteArray> sign(const QByteArray &content, const std::ve | |||
317 | return makeUnexpected(result.error()); | 318 | return makeUnexpected(result.error()); |
318 | } | 319 | } |
319 | 320 | ||
320 | return resultData; | 321 | auto algo = result.createdSignature(0).hashAlgorithmAsString(); |
322 | // RFC 3156 Section 5: | ||
323 | // Hash-symbols are constructed [...] by converting the text name to lower | ||
324 | // case and prefixing it with the four characters "pgp-". | ||
325 | auto micAlg = (QString("pgp-") + algo).toLower(); | ||
326 | |||
327 | return std::pair<QByteArray, QString>{resultData, micAlg}; | ||
321 | } | 328 | } |
322 | 329 | ||
323 | /** | 330 | /** |
324 | * Create a message like this (according to RFC 3156 Section 5): | 331 | * Create a message part like this (according to RFC 3156 Section 5): |
325 | * | 332 | * |
326 | * + `multipart/signed` | 333 | * + `multipart/signed` |
327 | * - whatever the given original `message` is (should be canonicalized) | 334 | * - whatever the given original `message` is (should be canonicalized) |
@@ -332,16 +339,17 @@ Expected<GpgME::Error, QByteArray> sign(const QByteArray &content, const std::ve | |||
332 | * | 339 | * |
333 | * The signature can be generated by the `sign` function. | 340 | * The signature can be generated by the `sign` function. |
334 | */ | 341 | */ |
335 | KMime::Content *createSignedPart(KMime::Content *message, const QByteArray &signature, const QString &micAlg) | 342 | std::unique_ptr<KMime::Content> createSignedPart( |
343 | std::unique_ptr<KMime::Content> message, const QByteArray &signature, const QString &micAlg) | ||
336 | { | 344 | { |
337 | KMime::Content *result = new KMime::Content; | 345 | auto result = std::unique_ptr<KMime::Content>(new KMime::Content); |
338 | 346 | ||
339 | result->contentType()->setMimeType("multipart/signed"); | 347 | result->contentType()->setMimeType("multipart/signed"); |
340 | result->contentType()->setBoundary(KMime::multiPartBoundary()); | 348 | result->contentType()->setBoundary(KMime::multiPartBoundary()); |
341 | result->contentType()->setParameter("micalg", micAlg); | 349 | result->contentType()->setParameter("micalg", micAlg); |
342 | result->contentType()->setParameter("protocol", "application/pgp-signature"); | 350 | result->contentType()->setParameter("protocol", "application/pgp-signature"); |
343 | 351 | ||
344 | result->addContent(message); | 352 | result->addContent(message.release()); |
345 | 353 | ||
346 | KMime::Content *signedPartPart = new KMime::Content; | 354 | KMime::Content *signedPartPart = new KMime::Content; |
347 | { | 355 | { |
@@ -371,12 +379,13 @@ KMime::Content *createSignedPart(KMime::Content *message, const QByteArray &sign | |||
371 | * - `application/pgp-keys` (the public key as attachment, which is the first of the | 379 | * - `application/pgp-keys` (the public key as attachment, which is the first of the |
372 | * `signingKeys`) | 380 | * `signingKeys`) |
373 | */ | 381 | */ |
374 | Expected<GpgME::Error, KMime::Content *> createSignedEmail(KMime::Content *content, | 382 | Expected<GpgME::Error, std::unique_ptr<KMime::Content>> |
383 | createSignedEmail(std::unique_ptr<KMime::Content> content, | ||
375 | const std::vector<GpgME::Key> &signingKeys, const GpgME::Key &attachedKey) | 384 | const std::vector<GpgME::Key> &signingKeys, const GpgME::Key &attachedKey) |
376 | { | 385 | { |
377 | Q_ASSERT(!signingKeys.empty()); | 386 | Q_ASSERT(!signingKeys.empty()); |
378 | 387 | ||
379 | auto contentToSign = canonicalizeContent(content); | 388 | auto contentToSign = canonicalizeContent(content.get()); |
380 | 389 | ||
381 | auto signingResult = sign(contentToSign, signingKeys); | 390 | auto signingResult = sign(contentToSign, signingKeys); |
382 | 391 | ||
@@ -384,33 +393,29 @@ Expected<GpgME::Error, KMime::Content *> createSignedEmail(KMime::Content *conte | |||
384 | return makeUnexpected(signingResult.error()); | 393 | return makeUnexpected(signingResult.error()); |
385 | } | 394 | } |
386 | 395 | ||
387 | auto signedData = signingResult.value(); | 396 | QByteArray signingData; |
397 | QString micAlg; | ||
398 | std::tie(signingData, micAlg) = signingResult.value(); | ||
388 | 399 | ||
389 | KMime::Content *signedPart = createSignedPart(content, signedData, "TODO: pgp-something"); | 400 | auto signedPart = createSignedPart(std::move(content), signingData, micAlg); |
390 | 401 | ||
391 | auto publicKeyAppendResult = appendPublicKey(signedPart, attachedKey); | 402 | auto publicKeyAppendResult = appendPublicKey(std::move(signedPart), attachedKey); |
392 | 403 | ||
393 | // TODO: this is ugly (maybe use a std::unique_ptr for signedPart) | 404 | if (publicKeyAppendResult) { |
394 | if (!publicKeyAppendResult) { | 405 | publicKeyAppendResult.value()->assemble(); |
395 | delete signedPart; | ||
396 | } | 406 | } |
397 | 407 | ||
398 | return publicKeyAppendResult; | 408 | return publicKeyAppendResult; |
399 | } | 409 | } |
400 | 410 | ||
401 | KMime::Content *MailCrypto::processCrypto(KMime::Content *content, | 411 | Expected<GpgME::Error, std::unique_ptr<KMime::Content>> |
402 | const std::vector<GpgME::Key> &signingKeys, const std::vector<GpgME::Key> &encryptionKeys, | 412 | MailCrypto::processCrypto(std::unique_ptr<KMime::Content> content, const std::vector<GpgME::Key> &signingKeys, |
403 | const GpgME::Key &attachedKey) | 413 | const std::vector<GpgME::Key> &encryptionKeys, const GpgME::Key &attachedKey) |
404 | { | 414 | { |
405 | 415 | if (!encryptionKeys.empty()) { | |
406 | qDebug() << "Attaching key:" << attachedKey.shortKeyID() << "from processCrypto"; | 416 | return createEncryptedEmail(content.release(), encryptionKeys, attachedKey, signingKeys); |
407 | 417 | } else if (!signingKeys.empty()) { | |
408 | if(!encryptionKeys.empty()) { | 418 | return createSignedEmail(std::move(content), signingKeys, signingKeys[0]); |
409 | // TODO | ||
410 | return createEncryptedEmail(content, encryptionKeys, attachedKey, signingKeys).value(); | ||
411 | } else if(!signingKeys.empty()) { | ||
412 | // TODO | ||
413 | return createSignedEmail(content, signingKeys, signingKeys[0]).value(); | ||
414 | } else { | 419 | } else { |
415 | qWarning() << "Processing cryptography, but neither signing nor encrypting"; | 420 | qWarning() << "Processing cryptography, but neither signing nor encrypting"; |
416 | return content; | 421 | return content; |
diff --git a/framework/src/domain/mime/mailcrypto.h b/framework/src/domain/mime/mailcrypto.h index 89343fc9..832f68ec 100644 --- a/framework/src/domain/mime/mailcrypto.h +++ b/framework/src/domain/mime/mailcrypto.h | |||
@@ -19,14 +19,20 @@ | |||
19 | 19 | ||
20 | #pragma once | 20 | #pragma once |
21 | 21 | ||
22 | #include "framework/src/errors.h" | ||
23 | |||
22 | #include <KMime/Message> | 24 | #include <KMime/Message> |
25 | #include <gpgme++/key.h> | ||
26 | |||
23 | #include <QByteArray> | 27 | #include <QByteArray> |
28 | |||
24 | #include <functional> | 29 | #include <functional> |
25 | #include <gpgme++/key.h> | 30 | #include <memory> |
26 | 31 | ||
27 | namespace MailCrypto { | 32 | namespace MailCrypto { |
28 | 33 | ||
29 | KMime::Content *processCrypto(KMime::Content *content, const std::vector<GpgME::Key> &signingKeys, | 34 | Expected<GpgME::Error, std::unique_ptr<KMime::Content>> |
35 | processCrypto(std::unique_ptr<KMime::Content> content, const std::vector<GpgME::Key> &signingKeys, | ||
30 | const std::vector<GpgME::Key> &encryptionKeys, const GpgME::Key &attachedKey); | 36 | const std::vector<GpgME::Key> &encryptionKeys, const GpgME::Key &attachedKey); |
31 | 37 | ||
32 | std::vector<GpgME::Key> findKeys(const QStringList &filter, bool findPrivate = false, bool remote = false); | 38 | std::vector<GpgME::Key> findKeys(const QStringList &filter, bool findPrivate = false, bool remote = false); |
diff --git a/framework/src/domain/mime/mailtemplates.cpp b/framework/src/domain/mime/mailtemplates.cpp index 09932e86..997eb3ae 100644 --- a/framework/src/domain/mime/mailtemplates.cpp +++ b/framework/src/domain/mime/mailtemplates.cpp | |||
@@ -1093,13 +1093,12 @@ KMime::Message::Ptr MailTemplates::createMessage(KMime::Message::Ptr existingMes | |||
1093 | 1093 | ||
1094 | QByteArray bodyData; | 1094 | QByteArray bodyData; |
1095 | if (!signingKeys.empty() || !encryptionKeys.empty()) { | 1095 | if (!signingKeys.empty() || !encryptionKeys.empty()) { |
1096 | auto result = MailCrypto::processCrypto( | 1096 | auto result = MailCrypto::processCrypto(std::move(bodyPart), signingKeys, encryptionKeys, attachedKey); |
1097 | bodyPart.get(), signingKeys, encryptionKeys, attachedKey); | ||
1098 | if (!result) { | 1097 | if (!result) { |
1099 | qWarning() << "Signing failed"; | 1098 | qWarning() << "Crypto failed"; |
1100 | return {}; | 1099 | return {}; |
1101 | } | 1100 | } |
1102 | bodyData = result->encodedContent(); | 1101 | bodyData = result.value()->encodedContent(); |
1103 | } else { | 1102 | } else { |
1104 | if (!bodyPart->contentType(false)) { | 1103 | if (!bodyPart->contentType(false)) { |
1105 | bodyPart->contentType(true)->setMimeType("text/plain"); | 1104 | bodyPart->contentType(true)->setMimeType("text/plain"); |