Tizen 2.0 Release
[platform/core/messaging/email-service.git] / email-core / email-core-smime.c
1 /*
2 *  email-service
3 *
4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5 *
6 * Contact: Kyuho Jo <kyuho.jo@samsung.com>, Sunghyun Kwon <sh0701.kwon@samsung.com>
7
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
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
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.
19 *
20 */
21
22
23
24 /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***
25  *File :  email-core-smime.c
26  *Desc :  MIME Operation
27  *
28  *Auth :
29  *
30  *History :
31  *   2011.04.14  :  created
32  ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/
33 #undef close
34
35 #include <openssl/pkcs7.h>
36 #include <openssl/pkcs12.h>
37 #include <openssl/buffer.h>
38 #include <openssl/pem.h>
39 #include <openssl/err.h>
40
41 #include "email-utilities.h"
42 #include "email-core-global.h"
43 #include "email-core-utils.h"
44 #include "email-core-mail.h"
45 #include "email-core-smtp.h"
46 #include "email-storage.h"
47 #include "email-core-smime.h"
48 #include "email-core-cert.h"
49 #include "email-debug-log.h"
50
51 /* /opt/share/cert-svc/certs is a base path */
52
53 #define SMIME_SIGNED_FILE "smime.p7s"
54 #define SMIME_ENCRYPT_FILE "smime.p7m"
55 #define DECRYPT_TEMP_FILE "decrypt_temp_file.eml"
56
57 /* If not present then the default digest algorithm for signing key will be used SHA1 */
58 static const EVP_MD *emcore_get_digest_algorithm(email_digest_type digest_type)
59 {
60         const EVP_MD *digest_algo = NULL;
61         
62         switch (digest_type) {
63         case DIGEST_TYPE_MD5:
64                 digest_algo = EVP_md5();
65                 break;
66         case DIGEST_TYPE_SHA1:
67         default:
68                 digest_algo = EVP_sha1();
69                 break;
70         }
71
72         return digest_algo;
73 }
74
75 /* If not present then the default cipher algorithm for signing key will be used RC2(40) */
76 static const EVP_CIPHER *emcore_get_cipher_algorithm(email_cipher_type cipher_type)
77 {
78         const EVP_CIPHER *cipher = NULL;
79
80         switch (cipher_type) {
81         case CIPHER_TYPE_RC2_128 :
82                 cipher = EVP_rc2_cbc();
83                 break;
84         case CIPHER_TYPE_RC2_64 :
85                 cipher = EVP_rc2_64_cbc();
86                 break;
87         case CIPHER_TYPE_DES3 :
88                 cipher = EVP_des_ede3_cbc();
89                 break;
90         case CIPHER_TYPE_DES :
91                 cipher = EVP_des_cbc();
92                 break;
93 #ifdef __FEATURE_USE_MORE_CIPHER_TYPE__
94         case CIPHER_TYPE_SEED :
95                 cipher = EVP_seed_cbc();
96                 break;
97         case CIPHER_TYPE_AES128 :
98                 cipher = EVP_aes_128_cbc();
99                 break;
100         case CIPHER_TYPE_AES192 :
101                 cipher = EVP_aes_192_cbc();
102                 break;
103         case CIPHER_TYPE_AES256 :
104                 cipher = EVP_aes_256_cbc();
105                 break;
106 #ifndef OPENSSL_NO_CAMELLIA             
107         case CIPHER_TYPE_CAMELLIA128 :
108                 cipher = EVP_camellia_128_cbc();
109                 break;
110         case CIPHER_TYPE_CAMELLIA192 :
111                 cipher = EVP_camellia_192_cbc();
112                 break;
113         case CIPHER_TYPE_CAMELLIA256 :
114                 cipher = EVP_camellia_256_cbc();
115                 break;
116 #endif
117 #endif
118         case CIPHER_TYPE_RC2_40 :
119         default :
120                 cipher = EVP_rc2_40_cbc();
121                 break;
122         }
123
124         return cipher;
125 }
126
127 static int get_x509_stack_of_recipient_certs(char *recipients, STACK_OF(X509) **output_recipient_certs, int *err_code)
128 {
129         EM_DEBUG_FUNC_BEGIN("recipients : [%s], STACK_OF(X509) : [%p]", recipients, output_recipient_certs);
130
131         int err = EMAIL_ERROR_NONE;
132         int ret = false;        
133         int cert_size = 0;
134         char *temp_recipients = NULL;
135         char *token = NULL;
136         char *str = NULL;
137         char file_name[512] = {0, };
138         const unsigned char *in_cert = NULL;
139
140         X509 *x509_cert = NULL;
141         STACK_OF(X509) *temp_recipient_certs = NULL;
142
143         CERT_CONTEXT *context = NULL;
144         emstorage_certificate_tbl_t *cert = NULL;
145
146         if (!recipients || !output_recipient_certs) {
147                 EM_DEBUG_EXCEPTION("Invalid parameter");
148                 err = EMAIL_ERROR_INVALID_PARAM;
149                 goto FINISH_OFF;
150         }
151
152         /* Initialize the variable */
153         context = cert_svc_cert_context_init();
154         temp_recipient_certs = sk_X509_new_null();
155
156         temp_recipients = EM_SAFE_STRDUP(recipients);
157         temp_recipients = em_replace_all_string(temp_recipients, ",", ";");     
158         token = strtok_r(temp_recipients, ";", &str);
159
160         do {
161                 if (!emstorage_get_certificate_by_email_address(token, &cert, false, 0, &err)) {
162                         EM_DEBUG_EXCEPTION("emstorage_get_certificate_by_email_address failed : [%d]", err);
163                         goto FINISH_OFF;
164                 }
165                 
166                 SNPRINTF(file_name, sizeof(file_name), "%s", cert->filepath);
167                 EM_DEBUG_LOG("file_name : [%s]", file_name);
168                 err = cert_svc_load_file_to_context(context, file_name);
169                 if (err != CERT_SVC_ERR_NO_ERROR) {
170                         EM_DEBUG_EXCEPTION("cert_svc_load_file_to_context failed : [%d]", err);
171                         err = EMAIL_ERROR_SYSTEM_FAILURE;
172                         goto FINISH_OFF;
173                 }
174
175                 in_cert = context->certBuf->data;
176                 cert_size = context->certBuf->size;
177
178                 if (d2i_X509(&x509_cert, &in_cert, cert_size) == NULL) {
179                         EM_DEBUG_EXCEPTION("d2i_X509 failed");
180                         err = EMAIL_ERROR_SYSTEM_FAILURE;
181                         goto FINISH_OFF;
182                 }
183
184                 if (!sk_X509_push(temp_recipient_certs, x509_cert)) {
185                         EM_DEBUG_EXCEPTION("sk_X509_push failed");
186                         err = EMAIL_ERROR_SYSTEM_FAILURE;
187                         goto FINISH_OFF;
188                 }
189
190                 x509_cert = NULL;
191                 context = NULL;
192                 emstorage_free_certificate(&cert, 1, NULL);
193                 cert = NULL;
194         } while ((token = strtok_r(NULL, ";", &str)));
195
196         *output_recipient_certs = temp_recipient_certs;
197
198         ret = true;
199
200 FINISH_OFF:
201
202         if (!ret) {
203                 if (x509_cert)
204                         X509_free(x509_cert);
205
206                 if (temp_recipient_certs)
207                         sk_X509_pop_free(temp_recipient_certs, X509_free);
208         }
209
210         if (cert)
211                 emstorage_free_certificate(&cert, 1, NULL);
212
213         cert_svc_cert_context_final(context);
214
215         EM_SAFE_FREE(temp_recipients);
216
217         if (err_code)
218                 *err_code = err;
219
220         return ret;
221 }
222
223 /* Opaque signed and encrypted method */
224 /*
225 static PKCS7 *opaque_signed_and_encrypt(STACK_OF(X509) *recipients_cert, X509 *signer, EVP_PKEY *private_key, BIO *mime_entity, const EVP_CIPHER *cipher, const EVP_MD *md, int flags)
226 {
227         EM_DEBUG_FUNC_BEGIN();
228         int i = 0;
229         PKCS7 *pkcs7 = NULL;
230         BIO *p7bio = NULL;
231         X509 *x509;
232
233         if (!(pkcs7 = PKCS7_new())) {
234                 EM_DEBUG_EXCEPTION("PKCS7 malloc failed");
235                 return NULL;
236         }
237         
238         if (!PKCS7_set_type(pkcs7, NID_pkcs7_signedAndEnveloped)) {
239                 EM_DEBUG_EXCEPTION("Set type failed");
240                 goto FINISH_OFF;
241         }
242
243         if (!PKCS7_add_signature(pkcs7, signer, private_key, md)) {
244                 EM_DEBUG_EXCEPTION("PKCS7_add_signature failed");
245                 goto FINISH_OFF;
246         }
247
248         if (!PKCS7_add_certificate(pkcs7, signer)) {
249                 EM_DEBUG_EXCEPTION("PKCS7_add_certificate failed");
250                 goto FINISH_OFF;
251         }
252
253         for (i = 0; i < sk_X509_num(recipients_cert); i++) {
254                 x509 = sk_X509_value(recipients_cert, i);
255                 if (!PKCS7_add_recipient(pkcs7, x509)) {
256                         EM_DEBUG_EXCEPTION("PKCS7_add_recipient failed");
257                         goto FINISH_OFF;
258                 }
259         }
260
261         if (!PKCS7_set_cipher(pkcs7, cipher)) {
262                 EM_DEBUG_EXCEPTION("Cipher failed");
263                 goto FINISH_OFF;
264         }
265
266         if (flags & PKCS7_STREAM)
267                 return pkcs7;
268
269         if (PKCS7_final(pkcs7, mime_entity, flags))
270                 return pkcs7;
271         
272 FINISH_OFF:
273         BIO_free_all(p7bio);
274         PKCS7_free(pkcs7);
275         return NULL;
276 }
277 */
278
279 INTERNAL_FUNC int emcore_smime_set_signed_message(char *certificate, char *mime_entity, email_digest_type digest_type, char **file_path, int *err_code)
280 {
281         EM_DEBUG_FUNC_BEGIN("certificate path : [%s], mime_entity : [%s]", certificate, mime_entity);
282         int err, ret = false;
283         char temp_smime_filepath[512];
284         X509 *cert = NULL;
285         STACK_OF(X509) *other_certs = NULL;
286         EVP_PKEY *private_key = NULL;
287         const EVP_MD *digest = NULL;
288         BIO *bio_mime_entity = NULL, *bio_cert = NULL, *bio_prikey = NULL;
289         BIO *smime_attachment = NULL;
290         PKCS7 *signed_message = NULL;
291         int flags = PKCS7_DETACHED | PKCS7_PARTIAL;
292
293         OpenSSL_add_all_algorithms();
294         ERR_load_crypto_strings();
295
296         SNPRINTF(temp_smime_filepath, sizeof(temp_smime_filepath), "%s%s%s", MAILTEMP, DIR_SEPERATOR, SMIME_SIGNED_FILE);
297         EM_DEBUG_LOG("attachment file path of smime : [%s]", temp_smime_filepath);
298
299         smime_attachment = BIO_new_file(temp_smime_filepath, OUTMODE);
300         if (!smime_attachment) {
301                 EM_DEBUG_EXCEPTION("Cannot open output file %s", temp_smime_filepath);
302                 err = EMAIL_ERROR_SYSTEM_FAILURE;
303                 goto FINISH_OFF;
304         }
305
306         /* Load certificate for getting the certificate and private key */
307         if (!emcore_load_PFX_file(certificate, &private_key, &cert, &other_certs, &err)) {
308                 EM_DEBUG_EXCEPTION("Load the private certificate failed : [%d]", err);
309                 goto FINISH_OFF;
310         }
311
312         bio_mime_entity = BIO_new_file(mime_entity, READMODE);
313         if (!bio_mime_entity) {
314                 EM_DEBUG_EXCEPTION("Cannot open file[%s]", mime_entity);
315                 err = EMAIL_ERROR_SYSTEM_FAILURE;
316                 goto FINISH_OFF;
317         }
318
319         signed_message = PKCS7_sign(NULL, NULL, other_certs, bio_mime_entity, flags);
320         if (!signed_message) {
321                 EM_DEBUG_EXCEPTION("Error creating PKCS#7 structure");
322                 err = EMAIL_ERROR_SYSTEM_FAILURE;
323                 goto FINISH_OFF;
324         }
325         
326         /* Get the digest algorithm */
327         digest = emcore_get_digest_algorithm(digest_type);
328
329         if (!PKCS7_sign_add_signer(signed_message, cert, private_key, digest, flags)) {
330                 EM_DEBUG_EXCEPTION("PKCS7_sign_add_signer failed");
331                 err = EMAIL_ERROR_SYSTEM_FAILURE;
332                 goto FINISH_OFF;
333         }
334
335         if (!PKCS7_final(signed_message, bio_mime_entity, flags)) {
336                 EM_DEBUG_EXCEPTION("PKCS7_final failed");
337                 err = EMAIL_ERROR_SYSTEM_FAILURE;
338                 goto FINISH_OFF;
339         }
340
341         if (!i2d_PKCS7_bio_stream(smime_attachment, signed_message, bio_mime_entity, flags)) {
342                 EM_DEBUG_EXCEPTION("i2d_PKCS7_bio_stream failed");
343                 err = EMAIL_ERROR_SYSTEM_FAILURE;
344                 goto FINISH_OFF;
345         }
346         BIO_flush(smime_attachment);
347         ret = true;
348
349 FINISH_OFF:
350         if (file_path && ret)
351                 *file_path = EM_SAFE_STRDUP(temp_smime_filepath);
352
353         X509_free(cert);
354         sk_X509_pop_free(other_certs, X509_free);
355         EVP_PKEY_free(private_key);
356         PKCS7_free(signed_message);
357
358         BIO_free(bio_mime_entity);
359         BIO_free(bio_cert);
360         BIO_free(bio_prikey);
361         BIO_free_all(smime_attachment);
362
363         EVP_cleanup();
364         if (err_code != NULL)
365                 *err_code = err;
366
367         EM_DEBUG_FUNC_END("err [%d]", err);
368         return ret;
369 }
370
371 INTERNAL_FUNC int emcore_smime_set_encrypt_message(char *recipient_list, char *mime_entity, email_cipher_type cipher_type, char **file_path, int *err_code)
372 {
373         EM_DEBUG_FUNC_BEGIN("certificate path : [%p], mime_entity : [%p]", recipient_list, mime_entity);
374         char temp_smime_filepath[512];
375         int err = EMAIL_ERROR_NONE, ret = false;
376 //      int flags = PKCS7_DETACHED | PKCS7_STREAM;
377         int flags = 0;
378
379         CERT_CONTEXT *loaded_cert = NULL;
380         STACK_OF(X509) *recipient_certs = NULL;
381         X509 *cert = NULL;
382         BIO *bio_mime_entity = NULL, *bio_cert = NULL;
383         BIO *smime_attachment = NULL;
384         PKCS7 *encrypt_message = NULL;
385         const EVP_CIPHER *cipher = NULL;
386
387         OpenSSL_add_all_algorithms();
388         ERR_load_crypto_strings();
389
390         loaded_cert = cert_svc_cert_context_init();
391
392         SNPRINTF(temp_smime_filepath, sizeof(temp_smime_filepath), "%s%s%s", MAILTEMP, DIR_SEPERATOR, SMIME_ENCRYPT_FILE);
393         EM_DEBUG_LOG("attachment file path of smime : [%s]", temp_smime_filepath);
394
395         smime_attachment = BIO_new_file(temp_smime_filepath, OUTMODE);
396         if (!smime_attachment) {
397                 EM_DEBUG_EXCEPTION("Cannot open output file %s", temp_smime_filepath);
398                 err = EMAIL_ERROR_SYSTEM_FAILURE;
399                 goto FINISH_OFF;
400         }
401
402         if (!get_x509_stack_of_recipient_certs(recipient_list, &recipient_certs, &err)) {
403                 EM_DEBUG_EXCEPTION("get_x509_stack_of_recipient_certs failed [%d]", err);
404                 goto FINISH_OFF;
405         }
406
407         bio_mime_entity = BIO_new_file(mime_entity, READMODE);
408         if (!bio_mime_entity) {
409                 EM_DEBUG_EXCEPTION("Cannot open file[%s]", mime_entity);
410                 goto FINISH_OFF;
411         }
412         
413         /* Get cipher algorithm */
414         cipher = emcore_get_cipher_algorithm(cipher_type);
415         
416         encrypt_message = PKCS7_encrypt(recipient_certs, bio_mime_entity, cipher, flags);
417         if (encrypt_message == NULL) {
418                 EM_DEBUG_EXCEPTION("PKCS7_encrypt failed [%ld]", ERR_get_error());
419                 err = EMAIL_ERROR_SYSTEM_FAILURE;
420                 goto FINISH_OFF;
421         }
422
423         if (!i2d_PKCS7_bio_stream(smime_attachment, encrypt_message, bio_mime_entity, flags)) {
424                 EM_DEBUG_EXCEPTION("i2d_PKCS7_bio_stream failed");
425                 err = EMAIL_ERROR_SYSTEM_FAILURE;
426                 goto FINISH_OFF;
427         }
428         BIO_flush(smime_attachment);
429
430         ret = true;
431
432 FINISH_OFF:
433         if (file_path && ret)
434                 *file_path = EM_SAFE_STRDUP(temp_smime_filepath);
435
436         PKCS7_free(encrypt_message);
437
438         X509_free(cert);
439         sk_X509_pop_free(recipient_certs, X509_free);
440
441         BIO_free(bio_cert);
442         BIO_free(bio_mime_entity);
443         BIO_free_all(smime_attachment);
444
445         cert_svc_cert_context_final(loaded_cert);
446         EVP_cleanup();
447         if (err_code != NULL)
448                 *err_code = err;
449
450         EM_DEBUG_FUNC_END("err [%d]", err);
451         return ret;
452 }
453
454 INTERNAL_FUNC int emcore_smime_set_signed_and_encrypt_message(char *recipient_list, char *certificate, char *mime_entity, email_cipher_type cipher_type, email_digest_type digest_type, char **file_path, int *err_code)
455 {
456         EM_DEBUG_FUNC_BEGIN("certificate path : [%s], mime_entity : [%s]", recipient_list, mime_entity);
457         char temp_smime_filepath[512];
458         int err = EMAIL_ERROR_NONE, ret = false;
459         int flags = PKCS7_DETACHED | PKCS7_PARTIAL | PKCS7_STREAM;
460
461         STACK_OF(X509) *recipient_certs = NULL;
462         STACK_OF(X509) *other_certs = NULL;
463         BIO *bio_mime_entity = NULL, *bio_cert = NULL;
464         BIO *bio_signed_message = BIO_new(BIO_s_mem());
465         BIO *smime_attachment = NULL;
466         PKCS7 *signed_message = NULL;
467         PKCS7 *encrypt_message = NULL;
468         const EVP_CIPHER *cipher = NULL;
469         const EVP_MD *digest = NULL;
470
471         /* Variable for private certificate */
472         EVP_PKEY *private_key = NULL;
473         X509 *cert = NULL;
474
475         OpenSSL_add_all_algorithms();
476         ERR_load_crypto_strings();
477
478         SNPRINTF(temp_smime_filepath, sizeof(temp_smime_filepath), "%s%s%s", MAILTEMP, DIR_SEPERATOR, SMIME_ENCRYPT_FILE);
479         EM_DEBUG_LOG("attachment file path of smime : [%s]", temp_smime_filepath);
480
481         smime_attachment = BIO_new_file(temp_smime_filepath, OUTMODE);
482         if (!smime_attachment) {
483                 EM_DEBUG_EXCEPTION("Cannot open output file %s", temp_smime_filepath);
484                 err = EMAIL_ERROR_SYSTEM_FAILURE;
485                 goto FINISH_OFF;
486         }
487
488         /* Signing the mail */
489         /* 1. Load the private certificate */
490         if (!emcore_load_PFX_file(certificate, &private_key, &cert, &other_certs, &err)) {
491                 EM_DEBUG_EXCEPTION("Load the private certificate failed : [%d]", err);
492                 goto FINISH_OFF;
493         }
494
495         /* 2. Read mime entity */
496         bio_mime_entity = BIO_new_file(mime_entity, READMODE);
497         if (!bio_mime_entity) {
498                 EM_DEBUG_EXCEPTION("Cannot open file[%s]", mime_entity);
499                 err = EMAIL_ERROR_SYSTEM_FAILURE;
500                 goto FINISH_OFF;
501         }
502
503         /* 3. signing */
504         signed_message = PKCS7_sign(NULL, NULL, other_certs, bio_mime_entity, flags);
505         if (!signed_message) {
506                 EM_DEBUG_EXCEPTION("Error creating PKCS#7 structure");
507                 err = EMAIL_ERROR_SYSTEM_FAILURE;
508                 goto FINISH_OFF;
509         }
510         
511         /* 4. Get the digest algorithm */
512         digest = emcore_get_digest_algorithm(digest_type);
513
514         /* 5. Apply a digest algorithm */
515         if (!PKCS7_sign_add_signer(signed_message, cert, private_key, digest, flags)) {
516                 EM_DEBUG_EXCEPTION("PKCS7_sign_add_signer failed");
517                 err = EMAIL_ERROR_SYSTEM_FAILURE;
518                 goto FINISH_OFF;
519         }
520
521         /* 6. Create signing message */
522         if (!SMIME_write_PKCS7(bio_signed_message, signed_message, bio_mime_entity, flags | SMIME_OLDMIME | SMIME_CRLFEOL)) {
523                 EM_DEBUG_EXCEPTION("SMIME_write_PKCS7 error");
524                 err = EMAIL_ERROR_SYSTEM_FAILURE;
525                 goto FINISH_OFF;
526         }
527
528         /* Encrypting the mail */
529         /* 1. Get the recipient certs */
530         if (!get_x509_stack_of_recipient_certs(recipient_list, &recipient_certs, &err)) {
531                 EM_DEBUG_EXCEPTION("get_x509_stack_of_recipient_certs failed [%d]", err);
532                 goto FINISH_OFF;
533         }
534
535         /* 2. Get cipher algorithm */
536         cipher = emcore_get_cipher_algorithm(cipher_type);
537         
538         flags = 0;
539
540         /* 3. Encrypt the signing message */    
541         encrypt_message = PKCS7_encrypt(recipient_certs, bio_signed_message, cipher, flags);
542         if (encrypt_message == NULL) {
543                 EM_DEBUG_EXCEPTION("PKCS7_encrypt failed [%ld]", ERR_get_error());
544                 err = EMAIL_ERROR_SYSTEM_FAILURE;
545                 goto FINISH_OFF;
546         }
547         
548         /* 4. Write the encrypt message in file */
549         if (!i2d_PKCS7_bio_stream(smime_attachment, encrypt_message, bio_mime_entity, flags)) {
550                 EM_DEBUG_EXCEPTION("i2d_PKCS7_bio_stream failed");
551                 err = EMAIL_ERROR_SYSTEM_FAILURE;
552                 goto FINISH_OFF;
553         }
554         BIO_flush(smime_attachment);
555
556         ret = true;
557
558 FINISH_OFF:
559         if (file_path && ret)
560                 *file_path = EM_SAFE_STRDUP(temp_smime_filepath);
561
562         PKCS7_free(signed_message);
563         PKCS7_free(encrypt_message);
564         EVP_PKEY_free(private_key);
565
566         X509_free(cert);
567         sk_X509_pop_free(other_certs, X509_free);
568         sk_X509_pop_free(recipient_certs, X509_free);
569
570         BIO_free(bio_cert);
571         BIO_free(bio_mime_entity);
572         BIO_free(bio_signed_message);
573         BIO_free_all(smime_attachment);
574
575         EVP_cleanup();
576         if (err_code != NULL)
577                 *err_code = err;
578
579         EM_DEBUG_FUNC_END("err [%d]", err);
580         return ret;
581 }
582
583
584
585 INTERNAL_FUNC int emcore_smime_set_decrypt_message(char *encrypt_message, char *certificate, char **decrypt_message, int *err_code)
586 {
587         EM_DEBUG_FUNC_BEGIN("encrypt_file : [%s], certificate : [%s]", encrypt_message, certificate);
588         int ret = false;
589         int err = EMAIL_ERROR_NONE;
590         char temp_decrypt_filepath[512] = {0, };
591
592         X509 *cert = NULL;
593         EVP_PKEY *private_key = NULL;
594         BIO *infile = NULL, *out_buf = NULL;
595         PKCS7 *p7_encrypt_message = NULL;
596         STACK_OF(X509) *recipient_certs = NULL;
597
598         OpenSSL_add_all_algorithms();
599
600         /* Load the encrypted message */
601         infile = BIO_new_file(encrypt_message, INMODE);
602         if (infile == NULL) {
603                 EM_DEBUG_EXCEPTION("Cannot open output file %s", encrypt_message);
604                 err = EMAIL_ERROR_SYSTEM_FAILURE;
605                 goto FINISH_OFF;
606         }
607
608         p7_encrypt_message = d2i_PKCS7_bio(infile, NULL);
609         if (!p7_encrypt_message) {
610                 EM_DEBUG_EXCEPTION("Error reading S/MIME message");
611                 err = EMAIL_ERROR_INVALID_PARAM;
612                 goto FINISH_OFF;
613         }
614
615         /* Initialize the output file for decrypted message */
616         SNPRINTF(temp_decrypt_filepath, sizeof(temp_decrypt_filepath), "%s%s%s", MAILTEMP, DIR_SEPERATOR, DECRYPT_TEMP_FILE);
617         EM_DEBUG_LOG("attachment file path of smime : [%s]", temp_decrypt_filepath);
618
619         out_buf = BIO_new_file(temp_decrypt_filepath, OUTMODE);
620         if (!out_buf) {
621                 EM_DEBUG_EXCEPTION("Cannot open output file %s", temp_decrypt_filepath);
622                 err = EMAIL_ERROR_SYSTEM_FAILURE;
623                 goto FINISH_OFF;
624         }
625
626         /* Search private cert */
627         if (!emcore_load_PFX_file(certificate, &private_key, &cert, NULL, &err)) {
628                 EM_DEBUG_EXCEPTION("Load the private certificate failed : [%d]", err);
629                 goto FINISH_OFF;
630         }
631
632         if (!PKCS7_decrypt(p7_encrypt_message, private_key, cert, out_buf, 0)) {
633                 EM_DEBUG_EXCEPTION("Decrpyt failed");
634                 err = EMAIL_ERROR_DECRYPT_FAILED;
635                 goto FINISH_OFF;
636         }
637
638         ret = true;
639
640 FINISH_OFF:
641
642         if (decrypt_message && ret)
643                 *decrypt_message = EM_SAFE_STRDUP(temp_decrypt_filepath);
644
645         EVP_cleanup();
646         X509_free(cert);
647         EVP_PKEY_free(private_key);
648         BIO_free(out_buf);
649         BIO_free_all(infile);
650         sk_X509_pop_free(recipient_certs, X509_free);
651
652         if (err_code != NULL)
653                 *err_code = err;
654
655         EM_DEBUG_FUNC_END("err [%d]", err);
656         return ret;
657 }
658
659 /*
660 INTERNAL_FUNC int emcore_smime_verify_signed_message(char *signed_message, char *ca_file, char *ca_path, int *verify)
661 {
662         int ret = false;
663         int temp_verify = 0;
664         BIO *indata = NULL;
665         BIO *content = NULL;
666         X509_STORE *store = NULL;
667         X509_LOOKUP *lookup = NULL;
668         PKCS7 *p7 = NULL;
669
670         OpenSSL_add_all_algorithms();
671         ERR_load_crypto_strings();
672
673         if (BIO_write(indata, signed_message, sizeof(signed_message)) <= 0) {
674                 EM_DEBUG_EXCEPTION("Char to Bio failed");
675                 goto FINISH_OFF;
676         }
677
678         p7 = SMIME_read_PKCS7(indata, &content);
679         if (!p7) {
680                 EM_DEBUG_EXCEPTION("SMIME_read_PKCS7 failed");
681                 goto FINISH_OFF;
682         }
683
684         if (!(store = X509_STORE_new())) {
685                 EM_DEBUG_EXCEPTION("Initialize x509_store failed");
686                 goto FINISH_OFF;
687         }
688         
689         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
690         if (lookup == NULL) {
691                 EM_DEBUG_EXCEPTION("Initialize lookup store failed");
692                 goto FINISH_OFF;
693         }
694
695         if (ca_file) {
696                 if (!X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM)) {
697                         EM_DEBUG_EXCEPTION("X509_LOOKUP_load_file failed");
698                         goto FINISH_OFF;
699                 }
700         } else {
701                 X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
702         }
703
704         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
705         if (lookup == NULL) {
706                 EM_DEBUG_EXCEPTION("X509_STORE_add_lookup failed");
707                 goto FINISH_OFF;
708         }
709         
710         if (ca_path) {
711                 if (!X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM)) {
712                         EM_DEBUG_EXCEPTION("CA path load failed");
713                         goto FINISH_OFF;
714                 }
715         } else {
716                 X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
717         }
718         
719         temp_verify = PKCS7_verify(p7, NULL, store, content, NULL, 0);
720         if (temp_verify) 
721                 EM_DEBUG_LOG("Verification Successful\n");
722
723         ret = true;
724
725 FINISH_OFF:
726         if (store)
727                 X509_STORE_free(store);
728         if (p7)
729                 PKCS7_free(p7);
730         
731         if (indata)
732                 BIO_free(indata);
733
734         if (verify != NULL)
735                 *verify = temp_verify;
736
737         ERR_clear_error();
738         EVP_cleanup();
739         return ret;
740 }
741 */
742
743 static char *emcore_set_mime_entity(char *mime_path)
744 {
745         EM_DEBUG_FUNC_BEGIN("mime_path : [%s]", mime_path);
746         FILE *fp_read = NULL;
747         FILE *fp_write = NULL;
748         char *mime_entity = NULL;
749         char *mime_entity_path = NULL;
750         char temp_buffer[255] = {0,};
751         int err;
752         int searched = 0;
753
754         if (!emcore_get_temp_file_name(&mime_entity_path, &err))  {
755                 EM_DEBUG_EXCEPTION(" em_core_get_temp_file_name failed[%d]", err);
756                 goto FINISH_OFF;
757         }
758
759         /* get mime entity */
760         if (mime_path != NULL) {
761                 fp_read = fopen(mime_path, "r");
762                 if (fp_read == NULL) {
763                         EM_DEBUG_EXCEPTION("File open(read) is failed : filename [%s]", mime_path);
764                         goto FINISH_OFF;
765                 }
766
767                 fp_write = fopen(mime_entity_path, "w");
768                 if (fp_write == NULL) {
769                         EM_DEBUG_EXCEPTION("File open(write) is failed : filename [%s]", mime_entity_path);
770                         goto FINISH_OFF;
771                 }
772
773                 fseek(fp_read, 0, SEEK_SET);
774                 fseek(fp_write, 0, SEEK_SET);           
775
776                 while (fgets(temp_buffer, 255, fp_read) != NULL) {
777                         mime_entity = strcasestr(temp_buffer, "content-type");
778                         if (mime_entity != NULL && !searched)
779                                 searched = 1;
780
781                         if (searched) {
782                                 EM_DEBUG_LOG("temp_buffer : %s", temp_buffer);
783                                 fprintf(fp_write, "%s", temp_buffer);
784                         }
785                 }
786         }       
787
788 FINISH_OFF:
789         if (fp_read)
790                 fclose(fp_read);
791
792         if (fp_write)
793                 fclose(fp_write);
794
795         EM_SAFE_FREE(mime_entity);
796         EM_SAFE_FREE(mime_path);
797
798         EM_DEBUG_FUNC_END();
799         return mime_entity_path;
800 }
801
802 INTERNAL_FUNC int emcore_convert_mail_data_to_smime_data(emstorage_account_tbl_t *account_tbl_item, email_mail_data_t *input_mail_data, email_attachment_data_t *input_attachment_data_list, int input_attachment_count, email_mail_data_t **output_mail_data, email_attachment_data_t **output_attachment_data_list, int *output_attachment_count)
803 {
804         EM_DEBUG_FUNC_BEGIN("input_mail_data[%p], input_attachment_data_list [%p], input_attachment_count [%d], output_mail_data [%p], output_attachment_data_list [%p]", input_mail_data, input_attachment_data_list, input_attachment_count, output_mail_data, output_attachment_data_list);
805
806         int ret = false;
807         int err = EMAIL_ERROR_NONE;
808         int smime_type = EMAIL_SMIME_NONE;
809         int address_length = 0;
810         int attachment_count = input_attachment_count;
811         int file_size = 0;
812         char *name = NULL;
813         char *rfc822_file = NULL;
814         char *mime_entity = NULL;
815         char *smime_file_path = NULL;
816         char *other_certificate_list = NULL;
817         email_attachment_data_t new_attachment_data = {0};
818         email_attachment_data_t *new_attachment_list = NULL;
819
820         /* Validating parameters */
821         
822         if (!input_mail_data || !(input_mail_data->account_id) || !(input_mail_data->mailbox_id)) {
823                 EM_DEBUG_EXCEPTION("EMAIL_ERROR_INVALID_PARAM");
824                 err = EMAIL_ERROR_INVALID_PARAM;
825                 goto FINISH_OFF;
826         }
827
828         if (!emcore_make_rfc822_file(input_mail_data, input_attachment_data_list, attachment_count, &rfc822_file, &err))  {
829                 EM_DEBUG_EXCEPTION("emcore_make_rfc822_file failed [%d]", err);
830                 goto FINISH_OFF;
831         }
832
833         mime_entity = emcore_set_mime_entity(rfc822_file);
834
835         smime_type = input_mail_data->smime_type;
836         if (!smime_type) 
837                 smime_type = account_tbl_item->smime_type;
838
839         /* Signed and Encrypt the message */
840         switch (smime_type) {
841         case EMAIL_SMIME_SIGNED:                        /* Clear signed message */
842                 if (!emcore_smime_set_signed_message(account_tbl_item->certificate_path, mime_entity, account_tbl_item->digest_type, &smime_file_path, &err)) {
843                         EM_DEBUG_EXCEPTION("em_core_smime_set_clear_signed_message is failed : [%d]", err);
844                         goto FINISH_OFF;
845                 }
846         
847                 EM_DEBUG_LOG("smime_file_path : %s", smime_file_path);  
848                 name = strrchr(smime_file_path, '/');
849
850                 new_attachment_data.attachment_name = EM_SAFE_STRDUP(name + 1);
851                 new_attachment_data.attachment_path = EM_SAFE_STRDUP(smime_file_path);
852
853                 attachment_count += 1;
854
855                 break;
856         case EMAIL_SMIME_ENCRYPTED:                     /* Encryption message */
857                 address_length = EM_SAFE_STRLEN(input_mail_data->full_address_to) + EM_SAFE_STRLEN(input_mail_data->full_address_cc) + EM_SAFE_STRLEN(input_mail_data->full_address_bcc);
858
859                 other_certificate_list = em_malloc(address_length + 3);
860                 
861                 SNPRINTF(other_certificate_list, address_length + 2, "%s;%s;%s", input_mail_data->full_address_to, input_mail_data->full_address_cc, input_mail_data->full_address_bcc);
862
863                 EM_DEBUG_LOG("to:[%s], cc:[%s], bcc:[%s]", input_mail_data->full_address_to, input_mail_data->full_address_cc, input_mail_data->full_address_bcc);
864                 EM_DEBUG_LOG("length : [%d], email_address : [%s]", address_length, other_certificate_list);
865
866                 if (!emcore_smime_set_encrypt_message(other_certificate_list, mime_entity, account_tbl_item->cipher_type, &smime_file_path, &err)) {
867                         EM_DEBUG_EXCEPTION("emcore_smime_set_encrypt_message is failed : [%d]", err);
868                         goto FINISH_OFF;
869                 }
870
871                 EM_DEBUG_LOG("smime_file_path : %s", smime_file_path);  
872                 name = strrchr(smime_file_path, '/');
873
874                 new_attachment_data.attachment_name = EM_SAFE_STRDUP(name + 1);
875                 new_attachment_data.attachment_path = EM_SAFE_STRDUP(smime_file_path);
876
877                 attachment_count = 1;
878
879                 break;
880         default:                        /* Signed and Encryption message */
881                 address_length = EM_SAFE_STRLEN(input_mail_data->full_address_to) + EM_SAFE_STRLEN(input_mail_data->full_address_cc) + EM_SAFE_STRLEN(input_mail_data->full_address_bcc);
882
883                 other_certificate_list = em_malloc(address_length + 3);
884
885                 SNPRINTF(other_certificate_list, address_length + 2, "%s;%s;%s", input_mail_data->full_address_to, input_mail_data->full_address_cc, input_mail_data->full_address_bcc);
886
887                 EM_DEBUG_LOG("to:[%s], cc:[%s], bcc:[%s]", input_mail_data->full_address_to, input_mail_data->full_address_cc, input_mail_data->full_address_bcc);
888                 EM_DEBUG_LOG("length : [%d], email_address : [%s]", address_length, other_certificate_list);
889
890                 if (!emcore_smime_set_signed_and_encrypt_message(other_certificate_list, account_tbl_item->certificate_path, mime_entity, account_tbl_item->cipher_type, account_tbl_item->digest_type, &smime_file_path, &err)) {
891                         EM_DEBUG_EXCEPTION("em_core_smime_set_signed_and_encrypt_message is failed : [%d]", err);
892                         goto FINISH_OFF;
893                 }
894
895                 EM_DEBUG_LOG("smime_file_path : %s", smime_file_path);  
896                 name = strrchr(smime_file_path, '/');
897
898                 new_attachment_data.attachment_name = EM_SAFE_STRDUP(name + 1);
899                 new_attachment_data.attachment_path = EM_SAFE_STRDUP(smime_file_path);
900
901                 attachment_count = 1;
902
903                 break;
904         }
905
906         if (!emcore_get_file_size(smime_file_path, &file_size, NULL)) {
907                 EM_DEBUG_EXCEPTION("emcore_get_file_size failed");
908                 goto FINISH_OFF;
909         }
910
911         new_attachment_data.attachment_size = file_size;
912         new_attachment_data.save_status = 1;
913
914         new_attachment_list = (email_attachment_data_t *)em_malloc(sizeof(email_attachment_data_t) * attachment_count);
915         if (new_attachment_list == NULL) {
916                 EM_DEBUG_EXCEPTION("em_malloc failed");
917                 goto FINISH_OFF;
918         }
919
920         if (input_attachment_data_list != NULL)
921                 new_attachment_list = input_attachment_data_list;
922
923         new_attachment_list[attachment_count-1] = new_attachment_data;
924
925         input_mail_data->smime_type = smime_type;
926         input_mail_data->file_path_mime_entity = EM_SAFE_STRDUP(mime_entity);
927         input_mail_data->digest_type = account_tbl_item->digest_type;
928
929         ret = true;
930
931 FINISH_OFF:     
932         if (output_attachment_count)
933                 *output_attachment_count = attachment_count;
934         
935         if (output_attachment_data_list) 
936                 *output_attachment_data_list = new_attachment_list;
937
938         *output_mail_data = input_mail_data;
939
940         return ret;                             
941 }
942
943