summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--framework/src/domain/mime/mailcrypto.cpp95
-rw-r--r--framework/src/domain/mime/mailcrypto.h10
-rw-r--r--framework/src/domain/mime/mailtemplates.cpp7
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 */
145Expected<GpgME::Error, KMime::Content *> appendPublicKey(KMime::Content *msg, const GpgME::Key &key) 145Expected<GpgME::Error, std::unique_ptr<KMime::Content>>
146appendPublicKey(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
196Expected<GpgME::Error, QByteArray> signAndEncrypt(const QByteArray &content, const std::vector<GpgME::Key> &signingKeys, 195Expected<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 */
230KMime::Content *createEncryptedPart(QByteArray encryptedData) 229std::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 */
279Expected<GpgME::Error, KMime::Content *> 278Expected<GpgME::Error, std::unique_ptr<KMime::Content>>
280createEncryptedEmail(KMime::Content *content, const std::vector<GpgME::Key> &encryptionKeys, 279createEncryptedEmail(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
307Expected<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 */
307Expected<GpgME::Error, std::pair<QByteArray, QString>>
308sign(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 */
335KMime::Content *createSignedPart(KMime::Content *message, const QByteArray &signature, const QString &micAlg) 342std::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 */
374Expected<GpgME::Error, KMime::Content *> createSignedEmail(KMime::Content *content, 382Expected<GpgME::Error, std::unique_ptr<KMime::Content>>
383createSignedEmail(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
401KMime::Content *MailCrypto::processCrypto(KMime::Content *content, 411Expected<GpgME::Error, std::unique_ptr<KMime::Content>>
402 const std::vector<GpgME::Key> &signingKeys, const std::vector<GpgME::Key> &encryptionKeys, 412MailCrypto::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
27namespace MailCrypto { 32namespace MailCrypto {
28 33
29KMime::Content *processCrypto(KMime::Content *content, const std::vector<GpgME::Key> &signingKeys, 34Expected<GpgME::Error, std::unique_ptr<KMime::Content>>
35processCrypto(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
32std::vector<GpgME::Key> findKeys(const QStringList &filter, bool findPrivate = false, bool remote = false); 38std::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");