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.
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>
38 #include <cert-svc/ccert.h>
39 #include <cert-svc/cstring.h>
40 #include <cert-svc/cpkcs12.h>
41 #include <cert-svc/cinstance.h>
42 #include <cert-svc/cprimitives.h>
44 #include "email-core-cert.h"
45 #include "email-core-mail.h"
46 #include "email-core-utils.h"
47 #include "email-utilities.h"
48 #include "email-storage.h"
49 #include "email-debug-log.h"
52 #define WRITE_MODE "w"
54 #define TRUSTED_USER "trusteduser/email/"
63 static int emcore_get_certificate_type(char *extension, int *err_code)
65 EM_DEBUG_FUNC_BEGIN("extensiong is [%s]", extension);
68 int err = EMAIL_ERROR_NONE;
69 char *supported_file_type[] = {"pfx", "p12", "p7s", "pem", "der", "crt", "cer", NULL};
72 EM_DEBUG_EXCEPTION("Invalid parameter");
73 err = EMAIL_ERROR_INVALID_PARAM;
77 while(supported_file_type[index]) {
78 EM_DEBUG_LOG_SEC("certificate extension[%d]:[%s]", index, supported_file_type[index]);
79 if (strcasecmp(extension, supported_file_type[index]) == 0) {
83 type = CERT_TYPE_PKCS12;
84 err = EMAIL_ERROR_INVALID_CERTIFICATE;
93 type = CERT_TYPE_PKCS7;
97 err = EMAIL_ERROR_INVALID_CERTIFICATE;
110 EM_DEBUG_FUNC_END("File type is [%d]", type);
114 static GList *emcore_make_glist_from_string(char *email_address_list)
116 EM_DEBUG_FUNC_BEGIN_SEC("email_address list : [%s]", email_address_list);
118 const gchar seperator = 0x01;
119 GList *email_list = NULL;
120 gchar *p_email_address_list = NULL;
121 gchar **token_list = NULL;
123 p_email_address_list = g_strdup(email_address_list);
125 token_list = g_strsplit(p_email_address_list, &seperator, -1);
126 while (token_list[index] != NULL) {
127 email_list = g_list_append(email_list, token_list[index]);
131 if (p_email_address_list)
132 g_free(p_email_address_list);
137 static char *emcore_store_public_certificate(STACK_OF(X509) *certificates, char *email_address, int *err_code)
139 EM_DEBUG_FUNC_BEGIN();
141 int err = EMAIL_ERROR_NONE;
142 char *file_path = NULL;
145 file_path = (char *)em_malloc(256);
146 if (file_path == NULL) {
147 EM_DEBUG_EXCEPTION("em_malloc failed");
148 err = EMAIL_ERROR_OUT_OF_MEMORY;
152 SNPRINTF(file_path, 256, "%s%s%s", CERT_SVC_STORE_PATH, TRUSTED_USER, email_address);
153 outfile = BIO_new_file(file_path, WRITE_MODE);
154 if (outfile == NULL) {
155 EM_DEBUG_EXCEPTION("File open failed[write mode]");
156 err = EMAIL_ERROR_SYSTEM_FAILURE;
160 for (index = 0; index < sk_X509_num(certificates); index++) {
161 EM_DEBUG_LOG("Write the certificate in pem file : [%d]", index);
162 PEM_write_bio_X509(outfile, sk_X509_value(certificates, index));
176 INTERNAL_FUNC int emcore_load_PFX_file(char *certificate, char *password, EVP_PKEY **pri_key, X509 **cert, STACK_OF(X509) **ca, int *err_code)
178 EM_DEBUG_FUNC_BEGIN_SEC("Certificate path : [%s], password : [%s]", certificate, password);
180 int err = EMAIL_ERROR_NONE;
185 err = em_fopen(certificate, "rb", &fp);
186 if (err != EMAIL_ERROR_NONE) {
187 EM_DEBUG_EXCEPTION_SEC("em_fopen failed : [%s] [%d]", certificate, err);
191 p12 = d2i_PKCS12_fp(fp, NULL);
193 EM_DEBUG_EXCEPTION("d2i_PKCS12_fp failed");
194 err = EMAIL_ERROR_SYSTEM_FAILURE;
198 if (!PKCS12_parse(p12, password, pri_key, cert, ca)) {
199 EM_DEBUG_EXCEPTION("PKCS12_parse failed");
200 err = EMAIL_ERROR_SYSTEM_FAILURE;
221 INTERNAL_FUNC int emcore_load_PFX_file(char *certificate, EVP_PKEY **pri_key, X509 **cert, STACK_OF(X509) **ca, int *err_code)
223 EM_DEBUG_FUNC_BEGIN_SEC("certificate : [%s]", certificate);
224 int err = EMAIL_ERROR_NONE;
227 char *private_key = NULL;
229 /* Variable for certificate */
232 // STACK_OF(X509) *t_ca = NULL;
234 /* Variable for private key */
235 EVP_PKEY *t_pri_key = NULL;
237 CertSvcString csstring;
238 CertSvcInstance cert_instance;
239 CertSvcCertificate csc_cert;
240 CertSvcCertificateList certificate_list;
241 CertSvcStoreCertList* certList = NULL;
242 CertSvcStoreCertList* tempList = NULL;
246 if (certificate == NULL) {
247 EM_DEBUG_EXCEPTION("Invalid parameter");
248 err = EMAIL_ERROR_INVALID_PARAM;
252 EM_DEBUG_EXCEPTION("emcore_load_PFX_file - certificate passed : %s", certificate);
254 /* Create instance */
255 err = certsvc_instance_new(&cert_instance);
256 if (err != CERTSVC_SUCCESS) {
257 EM_DEBUG_EXCEPTION("certsvc_instance_new failed : [%d]", err);
258 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
262 /* Make the pfxID string */
263 err = certsvc_string_new(cert_instance, certificate, EM_SAFE_STRLEN(certificate), &csstring);
264 if (err != CERTSVC_SUCCESS) {
265 EM_DEBUG_EXCEPTION("certsvc_string_new failed : [%d]", err);
266 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
270 if (certsvc_pkcs12_get_end_user_certificate_list_from_store(
274 &length) != CERTSVC_SUCCESS) {
275 EM_DEBUG_EXCEPTION("certsvc_string_new failed : [%d]", err);
276 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
282 if (strcmp(tempList->title, certificate) == 0
283 || strcmp(tempList->gname, certificate) == 0) {
284 alias = strdup(tempList->gname);
288 tempList = tempList->next;
291 certsvc_pkcs12_free_certificate_list_loaded_from_store(cert_instance, &certList);
293 EM_DEBUG_EXCEPTION("Failed to strdup");
294 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
298 /* Make the pfxID string */
299 err = certsvc_string_new(cert_instance, alias, EM_SAFE_STRLEN(alias), &csstring);
300 if (err != CERTSVC_SUCCESS) {
301 EM_DEBUG_EXCEPTION("certsvc_string_new failed : [%d]", err);
302 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
306 err = certsvc_pkcs12_load_certificate_list_from_store(cert_instance, EMAIL_STORE, csstring, &certificate_list);
307 if (err != CERTSVC_SUCCESS) {
308 certsvc_string_free(csstring);
309 err = certsvc_string_new(cert_instance, certificate, EM_SAFE_STRLEN(certificate), &csstring);
310 if (err != CERTSVC_SUCCESS) {
311 EM_DEBUG_EXCEPTION("certsvc_string_new failed : [%d]", err);
312 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
316 /* Load the certificate list of pkcs12 type */
317 err = certsvc_pkcs12_load_certificate_list_from_store(cert_instance, EMAIL_STORE, csstring, &certificate_list);
318 if (err != CERTSVC_SUCCESS) {
319 EM_DEBUG_EXCEPTION("certsvc_pkcs12_load_certificate_list_from_store failed : [%d]", err);
320 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
326 /* Get a certificate */
327 err = certsvc_certificate_list_get_one(certificate_list, 0, &csc_cert);
328 if (err != CERTSVC_SUCCESS) {
329 EM_DEBUG_EXCEPTION("certsvc_certificate_list_get_one failed : [%d]", err);
330 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
334 /* Convert from char to X509 */
335 err = certsvc_certificate_dup_x509(csc_cert, &t_cert);
336 if (t_cert == NULL || err != CERTSVC_SUCCESS) {
337 EM_DEBUG_EXCEPTION("certsvc_certificate_dup_x509 failed");
338 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
342 /* Get the private key */
343 err = certsvc_pkcs12_private_key_dup_from_store(cert_instance, EMAIL_STORE, csstring, &private_key, &key_size);
344 if (err != CERTSVC_SUCCESS) {
345 EM_DEBUG_EXCEPTION("certsvc_pkcs12_private_key_dup_from_store failed : [%d]", err);
346 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
350 EM_DEBUG_LOG_DEV("key_size : [%u], private_key : [%s]", key_size, private_key);
352 /* Convert char to pkey */
353 bio_mem = BIO_new(BIO_s_mem());
354 if (bio_mem == NULL) {
355 EM_DEBUG_EXCEPTION("malloc failed");
356 err = EMAIL_ERROR_OUT_OF_MEMORY;
360 if (BIO_write(bio_mem, private_key, (int)key_size) <= 0) {
361 EM_DEBUG_EXCEPTION("BIO_write failed");
362 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
366 t_pri_key = PEM_read_bio_PrivateKey(bio_mem, NULL, 0, NULL);
367 if (t_pri_key == NULL) {
368 EM_DEBUG_EXCEPTION("PEM_read_bio_PrivateKey failed");
369 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
385 *pri_key = t_pri_key;
388 EVP_PKEY_free(t_pri_key);
392 EM_SAFE_FREE(private_key);
400 certsvc_instance_free(cert_instance);
405 INTERNAL_FUNC int emcore_add_public_certificate(char *multi_user_name, char *public_cert_path, char *save_name, int *err_code)
407 EM_DEBUG_FUNC_BEGIN_SEC("Path [%s], filename [%s]", public_cert_path, save_name);
408 int err = EMAIL_ERROR_NONE;
412 char temp_file[512] = {0, };
413 char temp_save_name[512] = {0, };
414 char filepath[512] = {0, };
415 char *extension = NULL;
416 emstorage_certificate_tbl_t *cert = NULL;
417 CERT_CONTEXT *context = NULL;
419 if (public_cert_path == NULL || save_name == NULL) {
420 EM_DEBUG_EXCEPTION("Invalid parameter");
421 err = EMAIL_ERROR_INVALID_PARAM;
425 /* Initilize the structure of certificate */
426 context = cert_svc_cert_context_init();
428 /* Parse the file type */
429 extension = em_get_extension_from_file_path(public_cert_path, NULL);
430 if (extension == NULL) {
431 EM_DEBUG_EXCEPTION("Invalid parameter");
432 err = EMAIL_ERROR_INVALID_PARAM;
436 /* Get the file type information */
437 cert_type = emcore_get_certificate_type(extension, &err);
438 if (!cert_type || err == EMAIL_ERROR_INVALID_CERTIFICATE) {
439 EM_DEBUG_EXCEPTION("Invalid certificate");
443 /* Create temp file and rename */
444 if (cert_type == CERT_TYPE_P7S) {
448 SNPRINTF(temp_file, sizeof(temp_file), "%s%s%s.%s", MAILTEMP, DIR_SEPERATOR, save_name, extension);
449 EM_DEBUG_LOG_SEC("temp cert path : [%s]", temp_file);
451 if (!emstorage_copy_file(public_cert_path, temp_file, false, &err)) {
452 EM_DEBUG_EXCEPTION("emstorage_copy_file failed [%d]", err);
456 /* Load the public certificate */
457 err = cert_svc_load_file_to_context(context, temp_file);
458 if (err != CERT_SVC_ERR_NO_ERROR) {
459 EM_DEBUG_EXCEPTION("Load cert failed : [%d]", err);
460 err = EMAIL_ERROR_INVALID_CERTIFICATE;
464 /* Verify the certificate */
465 if (cert_svc_verify_certificate(context, &validity) != CERT_SVC_ERR_NO_ERROR) {
466 EM_DEBUG_EXCEPTION("cert_svc_verify_certificate failed");
467 // err = EMAIL_ERROR_INVALID_CERTIFICATE;
472 EM_DEBUG_LOG("Invalid certificate");
475 /* Load the certificate information */
476 if (cert_svc_extract_certificate_data(context) != CERT_SVC_ERR_NO_ERROR) {
477 EM_DEBUG_EXCEPTION("Extract the certificate failed");
478 err = EMAIL_ERROR_UNKNOWN;
482 /* Store the certificate file to trusted folder */
483 if (cert_svc_add_certificate_to_store(temp_file, TRUSTED_USER) != CERT_SVC_ERR_NO_ERROR) {
484 EM_DEBUG_EXCEPTION("Add certificate to trusted folder");
485 err = EMAIL_ERROR_UNKNOWN;
489 /* Store the certificate to DB */
490 SNPRINTF(filepath, sizeof(filepath), "%s%s%s.%s", CERT_SVC_STORE_PATH, TRUSTED_USER, save_name, extension);
491 SNPRINTF(temp_save_name, sizeof(temp_save_name), "<%s>", save_name);
493 cert = (emstorage_certificate_tbl_t *)em_malloc(sizeof(emstorage_certificate_tbl_t));
495 EM_DEBUG_EXCEPTION("em_malloc failed");
496 err = EMAIL_ERROR_OUT_OF_MEMORY;
500 cert->issue_year = context->certDesc->info.validPeriod.firstYear;
501 cert->issue_year = context->certDesc->info.validPeriod.firstYear;
502 cert->issue_month = context->certDesc->info.validPeriod.firstMonth;
503 cert->issue_day = context->certDesc->info.validPeriod.firstDay;
504 cert->expiration_year= context->certDesc->info.validPeriod.secondYear;
505 cert->expiration_month = context->certDesc->info.validPeriod.secondMonth;
506 cert->expiration_day = context->certDesc->info.validPeriod.secondDay;
507 cert->issue_organization_name = EM_SAFE_STRDUP(context->certDesc->info.issuer.organizationName);
508 cert->email_address = EM_SAFE_STRDUP(temp_save_name);
509 cert->subject_str = EM_SAFE_STRDUP(context->certDesc->info.issuerStr);
510 cert->filepath = EM_SAFE_STRDUP(filepath);
512 if (emstorage_add_certificate(multi_user_name, cert, true, &err)) {
513 EM_DEBUG_EXCEPTION("emstorage_add_certificate failed");
517 if (!emstorage_delete_file(public_cert_path, &err)) {
518 EM_DEBUG_EXCEPTION("emstorage_delete_file failed [%d]", err);
526 emstorage_delete_file(temp_file, NULL);
528 emstorage_free_certificate(&cert, 1, NULL);
530 cert_svc_cert_context_final(context);
532 if (err_code != NULL) {
542 INTERNAL_FUNC int emcore_delete_public_certificate(char *multi_user_name, char *email_address, int *err_code)
544 EM_DEBUG_FUNC_BEGIN();
546 int err = EMAIL_ERROR_NONE;
547 emstorage_certificate_tbl_t *certificate = NULL;
549 if (email_address == NULL) {
550 EM_DEBUG_EXCEPTION("Invalid parameter");
551 err = EMAIL_ERROR_INVALID_PARAM;
555 if (!emstorage_get_certificate_by_email_address(multi_user_name, email_address, &certificate, false, 0, &err)) {
556 EM_DEBUG_EXCEPTION("emstorage_get_certificate failed");
560 if (remove(certificate->filepath) < 0) {
561 EM_DEBUG_EXCEPTION_SEC("remove failed : [%s]", certificate->filepath);
565 if (!emstorage_delete_certificate(multi_user_name, certificate->certificate_id, true, &err)) {
566 EM_DEBUG_EXCEPTION("emstorage_delete_certificate failed");
573 if (certificate != NULL)
574 emstorage_free_certificate(&certificate, 1, NULL);
576 if (err_code != NULL)
584 INTERNAL_FUNC int emcore_verify_signature(char *p7s_file_path, char *mime_entity, int *validity, int *err_code)
586 EM_DEBUG_FUNC_BEGIN_SEC("path : [%s], mime_entity : [%s]", p7s_file_path, mime_entity);
588 int err = EMAIL_ERROR_NONE;
590 int flags = PKCS7_NOVERIFY;
594 BIO *bio_indata = NULL;
596 PKCS7 *pkcs7_p7s = NULL;
599 bio_p7s = BIO_new_file(p7s_file_path, INMODE);
601 EM_DEBUG_EXCEPTION("File open failed");
602 err = EMAIL_ERROR_SYSTEM_FAILURE;
606 /* Open input data file */
607 bio_indata = BIO_new_file(mime_entity, INMODE);
609 EM_DEBUG_EXCEPTION("File open failed");
610 err = EMAIL_ERROR_SYSTEM_FAILURE;
614 /* Load the p7s file */
615 pkcs7_p7s = d2i_PKCS7_bio(bio_p7s, NULL);
617 EM_DEBUG_EXCEPTION("d2i_PKCS7_bio failed");
618 err = EMAIL_ERROR_LOAD_CERTIFICATE_FAILURE;
622 if (!PKCS7_verify(pkcs7_p7s, NULL, NULL, bio_indata, NULL, flags)) {
623 EM_DEBUG_EXCEPTION("PKCS7_verify failed");
634 PKCS7_free(pkcs7_p7s);
640 BIO_free(bio_indata);
643 *validity = t_validity;
652 INTERNAL_FUNC int emcore_verify_certificate(char *certificate, int *validity, int *err_code)
654 EM_DEBUG_FUNC_BEGIN();
656 int err = EMAIL_ERROR_NONE;
659 CERT_CONTEXT *context = NULL;
661 context = cert_svc_cert_context_init();
663 err = cert_svc_load_file_to_context(context, certificate);
664 if (err != CERT_SVC_ERR_NO_ERROR) {
665 EM_DEBUG_EXCEPTION("Certificate load failed");
669 err = cert_svc_verify_certificate(context, &p_validity);
670 if (err != CERT_SVC_ERR_NO_ERROR) {
671 EM_DEBUG_EXCEPTION("Certificate verify failed");
679 if (validity != NULL)
680 *validity = p_validity;
682 if (err_code != NULL) {
686 cert_svc_cert_context_final(context);
692 INTERNAL_FUNC int emcore_free_certificate(email_certificate_t **certificate, int count, int *err_code)
694 EM_DEBUG_FUNC_BEGIN("certificate [%p], count [%d]", certificate, count);
696 if (count <= 0 || !certificate || !*certificate) {
697 EM_DEBUG_EXCEPTION("EMAIL_ERROR_INVALID_PARAM");
699 *err_code = EMAIL_ERROR_INVALID_PARAM;
703 email_certificate_t *p_certificate = *certificate;
706 for (i=0;i<count;i++) {
707 EM_SAFE_FREE(p_certificate[i].issue_organization_name);
708 EM_SAFE_FREE(p_certificate[i].email_address);
709 EM_SAFE_FREE(p_certificate[i].subject_str);
710 EM_SAFE_FREE(p_certificate[i].filepath);
713 EM_SAFE_FREE(p_certificate);
717 *err_code = EMAIL_ERROR_NONE;