4 * Copyright (c) 2000 - 2011 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.
23 /******************************************************************************
24 * File : email-core-cert.h
25 * Desc : Certificate API
30 * 2006.08.16 : created
31 *****************************************************************************/
32 #include <openssl/pkcs7.h>
33 #include <openssl/pkcs12.h>
34 #include <openssl/pem.h>
35 #include <openssl/err.h>
36 #include <cert-service.h>
39 #include "email-core-cert.h"
40 #include "email-core-mail.h"
41 #include "email-utilities.h"
42 #include "email-storage.h"
43 #include "email-debug-log.h"
46 #define WRITE_MODE "w"
48 #define EMAIL_ERROR_CERTIFICATE_LOAD_FAIL 2300
49 #define EMAIL_ERROR_FILE_NOT_OPEN 2301
50 #define EMAIL_ERROR_INVALID_CERTIFICATE 2302
52 #define TRUSTED_USER "trusteduser/email/"
61 static int emcore_get_certificate_type(char *extension, int *err_code)
63 EM_DEBUG_FUNC_BEGIN("extensiong is [%s]", extension);
66 int err = EMAIL_ERROR_NONE;
67 char *supported_file_type[] = {"pfx", "p12", "p7s", "pem", "der", "crt", "cer", NULL};
70 EM_DEBUG_EXCEPTION("Invalid parameter");
71 err = EMAIL_ERROR_INVALID_PARAM;
75 while(supported_file_type[index]) {
76 EM_DEBUG_LOG("certificate extension[%d]:[%s]", index, supported_file_type[index]);
77 if (strcasecmp(extension, supported_file_type[index]) == 0) {
81 type = CERT_TYPE_PKCS12;
82 err = EMAIL_ERROR_INVALID_CERTIFICATE;
91 type = CERT_TYPE_PKCS7;
95 err = EMAIL_ERROR_INVALID_CERTIFICATE;
108 EM_DEBUG_FUNC_END("File type is [%d]", type);
112 static GList *emcore_make_glist_from_string(char *email_address_list)
114 EM_DEBUG_FUNC_BEGIN("email_address list : [%s]", email_address_list);
116 const gchar seperator = 0x01;
117 GList *email_list = NULL;
118 gchar *p_email_address_list = NULL;
119 gchar **token_list = NULL;
121 p_email_address_list = g_strdup(email_address_list);
123 token_list = g_strsplit(p_email_address_list, &seperator, -1);
124 while (token_list[index] != NULL) {
125 email_list = g_list_append(email_list, token_list[index]);
129 if (p_email_address_list)
130 g_free(p_email_address_list);
135 static int emcore_load_public_of_p7s(CERT_CONTEXT *context, char *public_cert_path, STACK_OF(X509) **certificates, int *err_code)
137 EM_DEBUG_FUNC_BEGIN();
140 int err = EMAIL_ERROR_NONE;
142 unsigned char *cert_string = NULL;
146 STACK_OF(X509) *certs = NULL;
148 if (public_cert_path == NULL) {
149 EM_DEBUG_EXCEPTION("Invalid parameter");
150 err = EMAIL_ERROR_INVALID_PARAM;
154 OpenSSL_add_all_algorithms();
157 infile = BIO_new_file(public_cert_path, READ_MODE);
158 if (infile == NULL) {
159 EM_DEBUG_EXCEPTION("File open failed [%s]", public_cert_path);
160 err = EMAIL_ERROR_FILE_NOT_FOUND;
164 /* Load the p7s file */
165 pkcs7 = d2i_PKCS7_bio(infile, NULL);
167 EM_DEBUG_EXCEPTION("smime.p7s load failed");
168 err = EMAIL_ERROR_CERTIFICATE_LOAD_FAIL;
172 /* Extract the signature in pkcs7 */
173 certs = PKCS7_get0_signers(pkcs7, NULL, 0);
175 EM_DEBUG_EXCEPTION("smime.p7s extract failed");
176 err = EMAIL_ERROR_CERTIFICATE_LOAD_FAIL;
180 /* Change from the p7s to the pem file */
181 if (sk_X509_num(certs) > 1) {
182 EM_DEBUG_EXCEPTION("Has one or more signature.\nIt is not support");
183 err = EMAIL_ERROR_UNKNOWN;
187 cert = sk_X509_value(certs, 0);
188 cert_size = i2d_X509(cert, &cert_string);
190 EM_DEBUG_EXCEPTION("Fail to convert certificate");
191 err = EMAIL_ERROR_UNKNOWN;
195 /* Initilize the certificate and CERT_CONTEXT buffer */
196 cert_string = (unsigned char *)em_malloc(sizeof(unsigned char *) * cert_size);
197 if (cert_string == NULL) {
198 EM_DEBUG_EXCEPTION("em_malloc failed");
199 err = EMAIL_ERROR_OUT_OF_MEMORY;
203 context->certBuf = (cert_svc_mem_buff *)em_malloc(sizeof(cert_svc_mem_buff));
204 if (context->certBuf == NULL) {
205 EM_DEBUG_EXCEPTION("em_malloc failed");
206 err = EMAIL_ERROR_OUT_OF_MEMORY;
210 /* Set CERT_CONTEXT structure */
211 context->certBuf->data = cert_string;
212 context->certBuf->size = cert_size;
228 if (certificates != NULL)
229 *certificates = certs;
231 if (err_code != NULL)
237 EM_SAFE_FREE(cert_string);
247 static char *emcore_store_public_certificate(STACK_OF(X509) *certificates, char *email_address, int *err_code)
249 EM_DEBUG_FUNC_BEGIN();
251 int err = EMAIL_ERROR_NONE;
252 char *file_path = NULL;
255 file_path = (char *)em_malloc(256);
256 if (file_path == NULL) {
257 EM_DEBUG_EXCEPTION("em_malloc failed");
258 err = EMAIL_ERROR_OUT_OF_MEMORY;
262 SNPRINTF(file_path, 256, "%s%s%s", CERT_SVC_STORE_PATH, TRUSTED_USER, email_address);
263 outfile = BIO_new_file(file_path, WRITE_MODE);
264 if (outfile == NULL) {
265 EM_DEBUG_EXCEPTION("File open failed[write mode]");
266 err = EMAIL_ERROR_FILE_NOT_OPEN;
270 for (index = 0; index < sk_X509_num(certificates); index++) {
271 EM_DEBUG_LOG("Write the certificate in pem file : [%d]", index);
272 PEM_write_bio_X509(outfile, sk_X509_value(certificates, index));
285 INTERNAL_FUNC int emcore_load_PFX_file(char *certificate, char *password, EVP_PKEY **pri_key, X509 **cert, STACK_OF(X509) **ca, int *err_code)
287 EM_DEBUG_FUNC_BEGIN("Certificate path : [%s], password : [%s]", certificate, password);
289 int err = EMAIL_ERROR_NONE;
294 OpenSSL_add_all_algorithms();
295 ERR_load_crypto_strings();
296 if (!(fp = fopen(certificate, "rb"))) {
297 EM_DEBUG_EXCEPTION("fopen failed : [%s]", certificate);
298 err = EMAIL_ERROR_SYSTEM_FAILURE;
302 p12 = d2i_PKCS12_fp(fp, NULL);
304 EM_DEBUG_EXCEPTION("d2i_PKCS12_fp failed");
305 err = EMAIL_ERROR_SYSTEM_FAILURE;
309 if (!PKCS12_parse(p12, password, pri_key, cert, ca)) {
310 EM_DEBUG_EXCEPTION("PKCS12_parse failed");
311 err = EMAIL_ERROR_SYSTEM_FAILURE;
331 INTERNAL_FUNC int emcore_add_public_certificate(char *public_cert_path, char *save_name, int *err_code)
333 EM_DEBUG_FUNC_BEGIN("Path [%s], filename [%s]", public_cert_path, save_name);
334 int err = EMAIL_ERROR_NONE;
338 char temp_file[512] = {0, };
339 char temp_save_name[512] = {0, };
340 char filepath[512] = {0, };
341 char *extension = NULL;
342 emstorage_certificate_tbl_t *cert = NULL;
343 CERT_CONTEXT *context = NULL;
345 if (public_cert_path == NULL || save_name == NULL) {
346 EM_DEBUG_EXCEPTION("Invalid parameter");
347 err = EMAIL_ERROR_INVALID_PARAM;
351 /* Initilize the structure of certificate */
352 context = cert_svc_cert_context_init();
354 /* Parse the file type */
355 extension = em_get_extension_from_file_path(public_cert_path, NULL);
356 if (extension == NULL) {
357 EM_DEBUG_EXCEPTION("Invalid parameter");
358 err = EMAIL_ERROR_INVALID_PARAM;
362 /* Get the file type information */
363 cert_type = emcore_get_certificate_type(extension, &err);
364 if (!cert_type || err == EMAIL_ERROR_INVALID_CERTIFICATE) {
365 EM_DEBUG_EXCEPTION("Invalid certificate");
369 /* Create temp file and rename */
370 if (cert_type == CERT_TYPE_P7S) {
374 SNPRINTF(temp_file, sizeof(temp_file), "%s%s%s%s%s.%s", MAILHOME, DIR_SEPERATOR, MAILTEMP, DIR_SEPERATOR, save_name, extension);
375 EM_DEBUG_LOG("temp cert path : [%s]", temp_file);
377 if (!emstorage_copy_file(public_cert_path, temp_file, false, &err)) {
378 EM_DEBUG_EXCEPTION("emstorage_copy_file failed [%d]", err);
382 /* Load the public certificate */
383 err = cert_svc_load_file_to_context(context, temp_file);
384 if (err != CERT_SVC_ERR_NO_ERROR) {
385 EM_DEBUG_EXCEPTION("Load cert failed : [%d]", err);
386 err = EMAIL_ERROR_INVALID_CERTIFICATE;
390 /* Verify the certificate */
391 if (cert_svc_verify_certificate(context, &validity) != CERT_SVC_ERR_NO_ERROR) {
392 EM_DEBUG_EXCEPTION("cert_svc_verify_certificate failed");
393 // err = EMAIL_ERROR_INVALID_CERTIFICATE;
398 EM_DEBUG_LOG("Invalid certificate");
401 /* Load the certificate information */
402 if (cert_svc_extract_certificate_data(context) != CERT_SVC_ERR_NO_ERROR) {
403 EM_DEBUG_EXCEPTION("Extract the certificate failed");
404 err = EMAIL_ERROR_UNKNOWN;
408 /* Store the certificate file to trusted folder */
409 if (cert_svc_add_certificate_to_store(temp_file, TRUSTED_USER) != CERT_SVC_ERR_NO_ERROR) {
410 EM_DEBUG_EXCEPTION("Add certificate to trusted folder");
411 err = EMAIL_ERROR_UNKNOWN;
415 /* Store the certificate to DB */
416 SNPRINTF(filepath, sizeof(filepath), "%s%s%s.%s", CERT_SVC_STORE_PATH, TRUSTED_USER, save_name, extension);
417 SNPRINTF(temp_save_name, sizeof(temp_save_name), "<%s>", save_name);
419 cert = (emstorage_certificate_tbl_t *)em_malloc(sizeof(emstorage_certificate_tbl_t));
421 EM_DEBUG_EXCEPTION("em_malloc failed");
422 err = EMAIL_ERROR_OUT_OF_MEMORY;
426 cert->issue_year = context->certDesc->info.validPeriod.firstYear;
427 cert->issue_year = context->certDesc->info.validPeriod.firstYear;
428 cert->issue_month = context->certDesc->info.validPeriod.firstMonth;
429 cert->issue_day = context->certDesc->info.validPeriod.firstDay;
430 cert->expiration_year= context->certDesc->info.validPeriod.secondYear;
431 cert->expiration_month = context->certDesc->info.validPeriod.secondMonth;
432 cert->expiration_day = context->certDesc->info.validPeriod.secondDay;
433 cert->issue_organization_name = EM_SAFE_STRDUP(context->certDesc->info.issuer.organizationName);
434 cert->email_address = EM_SAFE_STRDUP(temp_save_name);
435 cert->subject_str = EM_SAFE_STRDUP(context->certDesc->info.issuerStr);
436 cert->filepath = EM_SAFE_STRDUP(filepath);
438 if (emstorage_add_certificate(cert, true, &err)) {
439 EM_DEBUG_EXCEPTION("emstorage_add_certificate failed");
443 if (!emstorage_delete_file(public_cert_path, &err)) {
444 EM_DEBUG_EXCEPTION("emstorage_delete_file failed [%d]", err);
452 emstorage_free_certificate(&cert, 1, NULL);
454 cert_svc_cert_context_final(context);
456 if (err_code != NULL) {
466 INTERNAL_FUNC int emcore_delete_public_certificate(char *email_address, int *err_code)
468 EM_DEBUG_FUNC_BEGIN();
470 int err = EMAIL_ERROR_NONE;
471 emstorage_certificate_tbl_t *certificate = NULL;
473 if (email_address == NULL) {
474 EM_DEBUG_EXCEPTION("Invalid parameter");
475 err = EMAIL_ERROR_INVALID_PARAM;
479 if (!emstorage_get_certificate_by_email_address(email_address, &certificate, false, 0, &err)) {
480 EM_DEBUG_EXCEPTION("emstorage_get_certificate failed");
484 if (remove(certificate->filepath) < 0) {
485 EM_DEBUG_EXCEPTION("remove failed : [%s]", certificate->filepath);
489 if (!emstorage_delete_certificate(certificate->certificate_id, true, &err)) {
490 EM_DEBUG_EXCEPTION("emstorage_delete_certificate failed");
497 if (certificate != NULL)
498 emstorage_free_certificate(&certificate, 1, NULL);
500 if (err_code != NULL)
508 INTERNAL_FUNC int emcore_verify_signature(char *p7s_file_path, char *mime_entity, int *validity, int *err_code)
510 EM_DEBUG_FUNC_BEGIN("path[%s], mime_entiy[%s]", p7s_file_path, mime_entity);
512 int err = EMAIL_ERROR_NONE;
517 unsigned char *msg = NULL;
519 unsigned char *sig = NULL;
520 unsigned char *tmp_sig = NULL;
525 CERT_CONTEXT *context = NULL;
527 context = cert_svc_cert_context_init();
529 if (!emcore_load_public_of_p7s(context, p7s_file_path, NULL, &err)) {
530 EM_DEBUG_EXCEPTION("emcore_load_public_of_p7s failed");
534 fp_msg = fopen(mime_entity, "rb");
535 fseek(fp_msg, 0L, SEEK_END);
536 msg_len = ftell(fp_msg);
537 fseek(fp_msg, 0L, SEEK_SET);
538 msg = (unsigned char *)em_malloc(sizeof(unsigned char) * (msg_len + 1));
540 EM_DEBUG_EXCEPTION("em_malloc failed");
541 err = EMAIL_ERROR_OUT_OF_MEMORY;
545 if ((f_size = fread(msg, sizeof(unsigned char), msg_len, fp_msg)) < 0) {
546 EM_DEBUG_EXCEPTION("File read failed");
550 fp_sig = fopen(p7s_file_path, "rb");
551 fseek(fp_sig, 0L, SEEK_END);
552 sig_len = ftell(fp_sig);
553 fseek(fp_sig, 0L, SEEK_SET);
554 sig = (unsigned char *)em_malloc(sizeof(unsigned char) * (sig_len + 1));
556 EM_DEBUG_EXCEPTION("em_malloc failed");
557 err = EMAIL_ERROR_OUT_OF_MEMORY;
560 tmp_sig = (unsigned char *)em_malloc(sizeof(unsigned char) * (sig_len + 1));
561 if (tmp_sig == NULL) {
562 EM_DEBUG_EXCEPTION("em_malloc failed");
563 err = EMAIL_ERROR_OUT_OF_MEMORY;
567 if ((f_size = fread(sig, sizeof(unsigned char), sig_len, fp_sig)) < 0) {
568 EM_DEBUG_EXCEPTION("File read failed");
572 for(i = 0; i < sig_len; i++) {
579 err = cert_svc_verify_signature(context, msg, msg_len, tmp_sig, NULL, &p_validity);
580 if (err != CERT_SVC_ERR_NO_ERROR) {
581 EM_DEBUG_EXCEPTION("Verify signature failed");
589 EM_SAFE_FREE(tmp_sig);
601 cert_svc_cert_context_final(context);
605 if (err_code != NULL)
612 INTERNAL_FUNC int emcore_verify_certificate(char *certificate, int *validity, int *err_code)
614 EM_DEBUG_FUNC_BEGIN();
616 int err = EMAIL_ERROR_NONE;
619 CERT_CONTEXT *context = NULL;
621 context = cert_svc_cert_context_init();
623 err = cert_svc_load_file_to_context(context, certificate);
624 if (err != CERT_SVC_ERR_NO_ERROR) {
625 EM_DEBUG_EXCEPTION("Certificate load failed");
629 err = cert_svc_verify_certificate(context, &p_validity);
630 if (err != CERT_SVC_ERR_NO_ERROR) {
631 EM_DEBUG_EXCEPTION("Certificate verify failed");
639 if (validity != NULL)
640 *validity = p_validity;
642 if (err_code != NULL) {
650 INTERNAL_FUNC int emcore_free_certificate(email_certificate_t **certificate, int count, int *err_code)
652 EM_DEBUG_FUNC_BEGIN("certificate [%p], count [%d]", certificate, count);
654 if (count <= 0 || !certificate || !*certificate) {
655 EM_DEBUG_EXCEPTION("EMAIL_ERROR_INVALID_PARAM");
657 *err_code = EMAIL_ERROR_INVALID_PARAM;
661 email_certificate_t *p_certificate = *certificate;
664 for (i=0;i<count;i++) {
665 EM_SAFE_FREE(p_certificate[i].issue_organization_name);
666 EM_SAFE_FREE(p_certificate[i].email_address);
667 EM_SAFE_FREE(p_certificate[i].subject_str);
668 EM_SAFE_FREE(p_certificate[i].filepath);
671 EM_SAFE_FREE(p_certificate);
675 *err_code = EMAIL_ERROR_NONE;