4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Kyuho Jo <kyuho.jo@samsung.com>, Sunghyun Kwon <sh0701.kwon@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
24 /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***
25 *File : email-core-smime.c
26 *Desc : MIME Operation
31 * 2011.04.14 : created
32 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/
36 #include <gmime/gmime.h>
47 #include <glib/gstdio.h>
49 #include "email-utilities.h"
50 #include "email-core-global.h"
51 #include "email-core-utils.h"
52 #include "email-core-mail.h"
53 #include "email-core-smtp.h"
54 #include "email-storage.h"
55 #include "email-core-cert.h"
56 #include "email-debug-log.h"
58 #define PGP_SIGNED_FILE "signature.asc"
59 #define PGP_ENCRYPTED_FILE "encrypted.asc"
60 #define DECRYPTED_TEMP_FILE "decrypted_temp_file.eml"
62 static char *passphrase = NULL;
64 static gboolean request_passwd(GMimeCryptoContext *ctx, const char *user_id,
65 const char *prompt_ctx, gboolean reprompt,
66 GMimeStream *response, GError **err)
68 EM_DEBUG_FUNC_BEGIN();
69 EM_DEBUG_LOG("passpharse : [%s]", passphrase);
70 if (g_mime_stream_write_string(response, passphrase) == -1 ||
71 g_mime_stream_write(response, "\n", 1) == -1) {
72 g_set_error(err, GMIME_ERROR, errno, "%s", g_strerror(errno));
76 EM_SAFE_FREE(passphrase);
82 static int emcore_pgp_get_gmime_digest_algo(email_digest_type digest_type)
84 EM_DEBUG_FUNC_BEGIN();
85 int gmime_digest_algo = GMIME_DIGEST_ALGO_DEFAULT;
87 switch (digest_type) {
88 case DIGEST_TYPE_SHA1:
89 gmime_digest_algo = GMIME_DIGEST_ALGO_SHA1;
92 gmime_digest_algo = GMIME_DIGEST_ALGO_MD5;
94 case DIGEST_TYPE_RIPEMD160:
95 gmime_digest_algo = GMIME_DIGEST_ALGO_RIPEMD160;
98 gmime_digest_algo = GMIME_DIGEST_ALGO_MD2;
100 case DIGEST_TYPE_TIGER192:
101 gmime_digest_algo = GMIME_DIGEST_ALGO_TIGER192;
103 case DIGEST_TYPE_HAVAL5160:
104 gmime_digest_algo = GMIME_DIGEST_ALGO_HAVAL5160;
106 case DIGEST_TYPE_SHA256:
107 gmime_digest_algo = GMIME_DIGEST_ALGO_SHA256;
109 case DIGEST_TYPE_SHA384:
110 gmime_digest_algo = GMIME_DIGEST_ALGO_SHA384;
112 case DIGEST_TYPE_SHA512:
113 gmime_digest_algo = GMIME_DIGEST_ALGO_SHA512;
115 case DIGEST_TYPE_SHA224:
116 gmime_digest_algo = GMIME_DIGEST_ALGO_SHA224;
118 case DIGEST_TYPE_MD4:
119 gmime_digest_algo = GMIME_DIGEST_ALGO_MD4;
122 gmime_digest_algo = GMIME_DIGEST_ALGO_DEFAULT;
127 return gmime_digest_algo;
130 static int get_stack_of_recipients(char *recipients, GPtrArray **output_recipients_array)
132 EM_DEBUG_FUNC_BEGIN();
133 int err = EMAIL_ERROR_NONE;
134 char *temp_key = NULL;
136 GPtrArray *p_recipients_array = NULL;
137 gchar **strings = NULL;
140 p_recipients_array = g_ptr_array_new();
141 if (p_recipients_array == NULL) {
142 EM_DEBUG_EXCEPTION("g_ptr_array_new failed");
143 err = EMAIL_ERROR_OUT_OF_MEMORY;
147 keys = EM_SAFE_STRDUP(recipients);
148 strings = g_strsplit(keys, ",", -1);
150 for (ptr = strings; *ptr; ptr++) {
152 temp_key = g_strdup_printf("0x%s", *(ptr));
153 g_ptr_array_add(p_recipients_array, temp_key);
159 if (err != EMAIL_ERROR_NONE)
160 g_ptr_array_free(p_recipients_array, true);
162 *output_recipients_array = p_recipients_array;
168 static GMimeSignatureStatus get_signature_status(GMimeSignatureList *signatures)
170 EM_DEBUG_FUNC_BEGIN();
174 GMimeSignature *sig = NULL;
175 GMimeSignatureStatus status = GMIME_SIGNATURE_STATUS_GOOD;
177 if (!signatures || signatures->array->len == 0)
178 return GMIME_SIGNATURE_STATUS_ERROR;
180 for (i = 0; i < g_mime_signature_list_length(signatures); i++) {
181 sig = g_mime_signature_list_get_signature(signatures, i);
182 if (sig) status = MAX(status, sig->status);
190 INTERNAL_FUNC int emcore_pgp_set_signed_message(char *certificate,
194 email_digest_type digest_type,
197 EM_DEBUG_FUNC_BEGIN_SEC("Certificate path : [%s], mime_entity : [%s]", certificate, mime_entity);
199 #ifdef __FEATURE_SECURE_PGP__
200 int err = EMAIL_ERROR_NONE;
203 int p_digest_type = 0;
204 char temp_pgp_filepath[512] = {0, };
206 GMimeCryptoContext *ctx = NULL;
207 GMimeStream *clear_text = NULL;
208 GMimeStream *signed_text = NULL;
209 GError *g_err = NULL;
211 if (!password || !mime_entity || !user_id) {
212 EM_DEBUG_EXCEPTION("Invalid param");
213 err = EMAIL_ERROR_INVALID_PARAM;
217 /* Initialized the output stream (signed stream) */
218 EM_SAFE_FREE(passphrase);
219 passphrase = EM_SAFE_STRDUP(password);
221 #if !GLIB_CHECK_VERSION(2, 31, 0)
226 SNPRINTF(temp_pgp_filepath, sizeof(temp_pgp_filepath), "%s%s%s", MAIL_TEMP, DIR_SEPERATOR, PGP_SIGNED_FILE);
227 EM_DEBUG_LOG_SEC("attachment file path of pgp : [%s]", temp_pgp_filepath);
229 err = em_open(temp_pgp_filepath, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH, &gpg_fd);
230 if (err != EMAIL_ERROR_NONE) {
231 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", temp_pgp_filepath, err);
235 signed_text = g_mime_stream_fs_new(gpg_fd);
236 if (g_mime_stream_reset(signed_text) == -1) {
237 EM_DEBUG_EXCEPTION("g_mime_stream_reset signed_text failed");
238 err = EMAIL_ERROR_SYSTEM_FAILURE;
242 ctx = g_mime_gpg_context_new(request_passwd, "/usr/bin/gpg");
243 g_mime_gpg_context_set_always_trust((GMimeGpgContext *)ctx, true);
245 /* Initialized the input stream (clear text stream) */
246 EM_DEBUG_LOG("mime_entity : [%s]", mime_entity);
247 err = em_open(mime_entity, O_RDONLY, 0, &clear_fd);
248 if (err != EMAIL_ERROR_NONE) {
249 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", mime_entity, err);
253 clear_text = g_mime_stream_fs_new(clear_fd);
254 if (g_mime_stream_reset(clear_text) == -1) {
255 EM_DEBUG_EXCEPTION("g_mime_stream_reset clear_text failed");
256 err = EMAIL_ERROR_SYSTEM_FAILURE;
260 /* Get the digest type of gmime */
261 p_digest_type = emcore_pgp_get_gmime_digest_algo(digest_type);
263 /* Set the signed message */
264 if ((g_mime_crypto_context_sign(ctx,
269 &g_err) < 0) && (g_err != NULL)) {
270 EM_DEBUG_EXCEPTION("g_mime_crypto_context_sign failed : [%s]", g_err->message);
271 err = EMAIL_ERROR_SYSTEM_FAILURE;
281 g_object_unref(clear_text);
284 g_object_unref(signed_text);
295 *file_path = EM_SAFE_STRDUP(temp_pgp_filepath);
298 #else /* __FEATURE_SECURE_PGP__ */
300 return EMAIL_ERROR_NOT_SUPPORTED;
305 INTERNAL_FUNC int emcore_pgp_set_encrypted_message(char *recipient_list,
310 email_digest_type digest_type,
313 EM_DEBUG_FUNC_BEGIN_SEC("Certificate path : [%s], mime_entity : [%s]", certificate, mime_entity);
315 #ifdef __FEATURE_SECURE_PGP__
316 int err = EMAIL_ERROR_NONE;
319 int p_digest_type = 0;
320 char temp_pgp_filepath[512] = {0, };
322 GPtrArray *recipients = NULL;
324 GMimeCryptoContext *ctx = NULL;
325 GMimeStream *clear_text = NULL;
326 GMimeStream *encrypted_text = NULL;
327 GError *g_err = NULL;
329 if (!recipient_list || !mime_entity || !user_id) {
330 EM_DEBUG_EXCEPTION("Invalid param");
331 err = EMAIL_ERROR_INVALID_PARAM;
335 /* Initialized the output stream (signed stream) */
336 #if !GLIB_CHECK_VERSION(2, 31, 0)
341 SNPRINTF(temp_pgp_filepath, sizeof(temp_pgp_filepath), "%s%s%s", MAIL_TEMP, DIR_SEPERATOR, PGP_ENCRYPTED_FILE);
342 EM_DEBUG_LOG_SEC("attachment file path of pgp : [%s]", temp_pgp_filepath);
344 err = em_open(temp_pgp_filepath, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH, &gpg_fd);
345 if (err != EMAIL_ERROR_NONE) {
346 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", temp_pgp_filepath, err);
350 encrypted_text = g_mime_stream_fs_new(gpg_fd);
351 if (g_mime_stream_reset(encrypted_text) == -1) {
352 EM_DEBUG_EXCEPTION("g_mime_stream_reset encrypted_text failed");
353 err = EMAIL_ERROR_SYSTEM_FAILURE;
357 ctx = g_mime_gpg_context_new(request_passwd, "/usr/bin/gpg");
358 g_mime_gpg_context_set_always_trust((GMimeGpgContext *)ctx, true);
360 /* Initialized the input stream (clear text stream) */
361 EM_DEBUG_LOG("mime_entity : [%s]", mime_entity);
362 err = em_open(mime_entity, O_RDONLY, 0, &clear_fd);
363 if (err != EMAIL_ERROR_NONE) {
364 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", mime_entity, err);
368 clear_text = g_mime_stream_fs_new(clear_fd);
369 if (g_mime_stream_reset(clear_text) == -1) {
370 EM_DEBUG_EXCEPTION("g_mime_stream_reset clear_text failed");
371 err = EMAIL_ERROR_SYSTEM_FAILURE;
375 /* Get the digest type of gmime */
376 p_digest_type = emcore_pgp_get_gmime_digest_algo(digest_type);
378 /* Set the recipients list */
379 if ((err = get_stack_of_recipients(recipient_list, &recipients)) != EMAIL_ERROR_NONE) {
380 EM_DEBUG_EXCEPTION("get_stack_of_recipients failed : [%d]", err);
384 /* Set the signed message */
385 if ((g_mime_crypto_context_encrypt(ctx,
392 &g_err) < 0) && (g_err != NULL)) {
393 EM_DEBUG_EXCEPTION("NO signature : g_mime_crypto_context_encrypt failed : [%s]", g_err->message);
394 err = EMAIL_ERROR_SYSTEM_FAILURE;
400 g_ptr_array_free(recipients, true);
406 g_object_unref(clear_text);
409 g_object_unref(encrypted_text);
420 *file_path = EM_SAFE_STRDUP(temp_pgp_filepath);
423 #else /* __FEATURE_SECURE_PGP__ */
425 return EMAIL_ERROR_NOT_SUPPORTED;
431 INTERNAL_FUNC int emcore_pgp_set_signed_and_encrypted_message(char *recipient_list,
436 email_digest_type digest_type,
439 EM_DEBUG_FUNC_BEGIN_SEC("mime_entity : [%s]", mime_entity);
441 #ifdef __FEATURE_SECURE_PGP__
442 int err = EMAIL_ERROR_NONE;
445 int p_digest_type = 0;
446 char temp_pgp_filepath[512] = {0, };
448 GPtrArray *recipients = NULL;
449 GMimeCryptoContext *ctx = NULL;
450 GMimeStream *clear_text = NULL;
451 GMimeStream *encrypted_text = NULL;
452 GError *g_err = NULL;
454 if (!recipient_list || !password || !mime_entity || !user_id) {
455 EM_DEBUG_EXCEPTION("Invalid param");
456 err = EMAIL_ERROR_INVALID_PARAM;
460 /* Initialized the output stream (signed stream) */
461 EM_SAFE_FREE(passphrase);
462 passphrase = strdup(password);
464 #if !GLIB_CHECK_VERSION(2, 31, 0)
469 SNPRINTF(temp_pgp_filepath, sizeof(temp_pgp_filepath), "%s%s%s", MAIL_TEMP, DIR_SEPERATOR, PGP_ENCRYPTED_FILE);
470 EM_DEBUG_LOG_SEC("attachment file path of pgp : [%s]", temp_pgp_filepath);
472 err = em_open(temp_pgp_filepath, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH, &gpg_fd);
473 if (err != EMAIL_ERROR_NONE) {
474 EM_DEBUG_EXCEPTION("em_open failed : [%s], [%d]", temp_pgp_filepath, err);
478 encrypted_text = g_mime_stream_fs_new(gpg_fd);
479 if (g_mime_stream_reset(encrypted_text) == -1) {
480 EM_DEBUG_EXCEPTION("g_mime_stream_reset encrypted_text failed");
481 err = EMAIL_ERROR_SYSTEM_FAILURE;
485 ctx = g_mime_gpg_context_new(request_passwd, "/usr/bin/gpg");
486 g_mime_gpg_context_set_always_trust((GMimeGpgContext *)ctx, true);
488 /* Initialized the input stream (clear text stream) */
489 EM_DEBUG_LOG("mime_entity : [%s]", mime_entity);
490 err = em_open(mime_entity, O_RDONLY, 0, &clear_fd);
491 if (err != EMAIL_ERROR_NONE) {
492 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", mime_entity, err);
496 clear_text = g_mime_stream_fs_new(clear_fd);
497 if (g_mime_stream_reset(clear_text) == -1) {
498 EM_DEBUG_EXCEPTION("g_mime_stream_reset clear_text failed");
499 err = EMAIL_ERROR_SYSTEM_FAILURE;
503 /* Get the digest type of gmime */
504 p_digest_type = emcore_pgp_get_gmime_digest_algo(digest_type);
506 /* Set the recipients list */
507 if ((err = get_stack_of_recipients(recipient_list, &recipients)) != EMAIL_ERROR_NONE) {
508 EM_DEBUG_EXCEPTION("get_stack_of_recipients failed : [%d]", err);
512 /* Set the signed message */
513 if ((g_mime_crypto_context_encrypt(ctx,
520 &g_err) < 0) && (g_err != NULL)) {
521 EM_DEBUG_EXCEPTION("Signature : g_mime_crypto_context_encrypt failed : [%s]", g_err->message);
522 err = EMAIL_ERROR_SYSTEM_FAILURE;
528 g_ptr_array_free(recipients, true);
534 g_object_unref(clear_text);
537 g_object_unref(encrypted_text);
548 *file_path = EM_SAFE_STRDUP(temp_pgp_filepath);
551 #else /* __FEATURE_SECURE_PGP__ */
553 return EMAIL_ERROR_NOT_SUPPORTED;
559 INTERNAL_FUNC int emcore_pgp_get_verify_signature(char *signature_path,
561 email_digest_type digest_type,
564 EM_DEBUG_FUNC_BEGIN_SEC("signature path : [%s], mime_entity : [%s]", signature_path, mime_entity);
566 #ifdef __FEATURE_SECURE_PGP__
567 int err = EMAIL_ERROR_NONE;
570 int p_digest_type = 0;
571 int p_verify = false;
573 GMimeCryptoContext *ctx = NULL;
574 GMimeStream *clear_text = NULL;
575 GMimeStream *signed_text = NULL;
576 GMimeSignatureList *signatures = NULL;
577 GError *g_err = NULL;
579 if (!signature_path || !mime_entity) {
580 EM_DEBUG_EXCEPTION("Invalid param");
581 err = EMAIL_ERROR_INVALID_PARAM;
585 /* Initialized the Context */
586 #if !GLIB_CHECK_VERSION(2, 31, 0)
591 ctx = g_mime_gpg_context_new(request_passwd, "/usr/bin/gpg");
592 g_mime_gpg_context_set_always_trust((GMimeGpgContext *)ctx, true);
594 /* Initialized the input stream (clear text stream) */
595 EM_DEBUG_LOG("mime_entity : [%s]", mime_entity);
596 err = em_open(mime_entity, O_RDONLY, 0, &clear_fd);
597 if (err != EMAIL_ERROR_NONE) {
598 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", mime_entity, err);
602 clear_text = g_mime_stream_fs_new(clear_fd);
603 if (g_mime_stream_reset(clear_text) == -1) {
604 EM_DEBUG_EXCEPTION("g_mime_stream_reset clear_text failed");
605 err = EMAIL_ERROR_SYSTEM_FAILURE;
609 /* Initialized the output stream (signed stream) */
610 EM_DEBUG_LOG("signature_path : [%s]", signature_path);
611 err = em_open(signature_path, O_RDONLY, 0, &signed_fd);
612 if (err != EMAIL_ERROR_NONE) {
613 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", signature_path, err);
617 signed_text = g_mime_stream_fs_new(signed_fd);
618 if (g_mime_stream_reset(signed_text) == -1) {
619 EM_DEBUG_EXCEPTION("g_mime_stream_reset signed_text failed");
620 err = EMAIL_ERROR_SYSTEM_FAILURE;
624 /* Get the digest type of gmime */
625 p_digest_type = emcore_pgp_get_gmime_digest_algo(digest_type);
627 /* Verify the signature */
628 signatures = g_mime_crypto_context_verify(ctx, p_digest_type, clear_text, signed_text, &g_err);
629 if (signatures == NULL) {
630 EM_DEBUG_EXCEPTION("g_mime_crypto_context_verify failed : [%s]", g_err->message);
631 err = EMAIL_ERROR_SYSTEM_FAILURE;
635 if (get_signature_status(signatures) != GMIME_SIGNATURE_STATUS_GOOD) {
636 EM_DEBUG_LOG("Invalid the signature");
648 g_object_unref(signatures);
651 g_object_unref(clear_text);
654 g_object_unref(signed_text);
668 #else /* __FEATURE_SECURE_PGP__ */
670 return EMAIL_ERROR_NOT_SUPPORTED;
676 INTERNAL_FUNC int emcore_pgp_get_decrypted_message(char *encrypted_message,
679 char **decrypted_file,
682 EM_DEBUG_FUNC_BEGIN_SEC("Encrypted message : [%s], password : [%s]", encrypted_message, password);
684 #ifdef __FEATURE_SECURE_PGP__
685 int err = EMAIL_ERROR_NONE;
686 int p_verify = false;
687 int decrypted_fd = 0;
688 int encrypted_fd = 0;
689 char temp_decrypt_filepath[512] = {0, };
691 GError *g_err = NULL;
692 GMimeCryptoContext *ctx = NULL;
693 GMimeDecryptResult *result = NULL;
694 GMimeStream *encrypted_text = NULL;
695 GMimeStream *decrypted_text = NULL;
697 if (!encrypted_message && !password) {
698 EM_DEBUG_EXCEPTION("Invalid parameter");
699 err = EMAIL_ERROR_INVALID_PARAM;
703 EM_SAFE_FREE(passphrase);
704 passphrase = EM_SAFE_STRDUP(password);
706 #if !GLIB_CHECK_VERSION(2, 31, 0)
711 /* Initialized the context */
712 ctx = g_mime_gpg_context_new(request_passwd, "/usr/bin/gpg");
713 g_mime_gpg_context_set_always_trust((GMimeGpgContext *)ctx, true);
715 /* Initialized the input stream (clear text stream) */
716 err = em_open(encrypted_message, O_RDONLY, 0, &encrypted_fd);
717 if (err != EMAIL_ERROR_NONE) {
718 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", encrypted_message, err);
722 encrypted_text = g_mime_stream_fs_new(encrypted_fd);
723 if (g_mime_stream_reset(encrypted_text) == -1) {
724 EM_DEBUG_EXCEPTION("g_mime_stream_reset encrypted_text failed");
725 err = EMAIL_ERROR_SYSTEM_FAILURE;
729 /* Initialized the output stream (signed stream) */
730 SNPRINTF(temp_decrypt_filepath, sizeof(temp_decrypt_filepath), "%s%s%s", MAIL_TEMP, DIR_SEPERATOR, DECRYPTED_TEMP_FILE);
731 EM_DEBUG_LOG_SEC("tmp decrypt file path : [%s]", temp_decrypt_filepath);
733 err = em_open(temp_decrypt_filepath, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH, &decrypted_fd);
734 if (err != EMAIL_ERROR_NONE) {
735 EM_DEBUG_EXCEPTION("em_open failed : [%s] [%d]", temp_decrypt_filepath, err);
739 decrypted_text = g_mime_stream_fs_new(decrypted_fd);
740 if (g_mime_stream_reset(decrypted_text) == -1) {
741 EM_DEBUG_EXCEPTION("g_mime_stream_reset decrypted_text failed");
742 err = EMAIL_ERROR_SYSTEM_FAILURE;
746 /* Get the decrypt message */
747 result = g_mime_crypto_context_decrypt(ctx, encrypted_text, decrypted_text, &g_err);
748 if (result == NULL) {
749 EM_DEBUG_EXCEPTION("g_mime_crypto_context_decrypt failed : [%s]", g_err->message);
750 err = EMAIL_ERROR_DECRYPT_FAILED;
754 if (result->signatures) {
755 if (get_signature_status(result->signatures) != GMIME_SIGNATURE_STATUS_GOOD)
772 g_object_unref(encrypted_text);
775 g_object_unref(decrypted_text);
778 g_object_unref(result);
789 *decrypted_file = EM_SAFE_STRDUP(temp_decrypt_filepath);
792 #else /* __FEATURE_SECURE_PGP__ */
794 return EMAIL_ERROR_NOT_SUPPORTED;