From 492c2388bfd0ee846171d365941854e3a8398bb6 Mon Sep 17 00:00:00 2001 From: Piotr Sawicki Date: Wed, 6 Sep 2017 09:22:36 +0200 Subject: [PATCH] Introduce certsvc_pkcs12_import_from_file_to_store_ret_list() This new function works in the same way as the certsvc_pkcs12_import_from_file_to_store does, but additionally it returns the list of imported certificates. Change-Id: Id8af8229e7e5dc0eedc208ec940c1e1e5430ab8d --- src/cert-svc/cpkcs12.h | 33 ++++++++++++ src/vcore/api.cpp | 36 +++++++++++-- src/vcore/pkcs12.cpp | 110 +++++++++++++++++++++++++++++++++++++--- src/vcore/pkcs12.h | 8 ++- tests/pkcs12/new_test_cases.cpp | 102 +++++++++++++++++++++++++++++++++++++ 5 files changed, 278 insertions(+), 11 deletions(-) diff --git a/src/cert-svc/cpkcs12.h b/src/cert-svc/cpkcs12.h index 101d2e3..5bd8c9f 100644 --- a/src/cert-svc/cpkcs12.h +++ b/src/cert-svc/cpkcs12.h @@ -282,6 +282,39 @@ int certsvc_pkcs12_import_from_file_to_store(CertSvcInstance instance, CertSvcString password, CertSvcString alias); + +/** + * Import PKCS#12 bundle(with .pfx or .p12) or certificate(base64 form with .crt + * or .pem suffix) from file to specified store and return imported list of certificates. + * If password isn't needed, create CertSvcString @a password with null input on + * certsvc_string_new(). Refer certsvc_string_new() API description + * + * @param[in] instance CertSvcInstance object + * @param[in] storeType cert-svc store type to query + * @param[in] path Path of the certificate which needs to be imported + * @param[in] password Password if the file to import is password-protected which can be + * empty CertSvcString in case of not-password-protected + * @param[in] alias Primary key for certificate bundle identification (can't be empty) + * @param[out] certList cert list in store returned in linked list. Free by + * certsvc_pkcs12_free_certificate_list_loaded_from_store() after use + * @param[out] length length of output @a certList + * + * @return #CERTSVC_SUCCESS on success, otherwise a zero or negative error value + * + * @see certsvc_instance_new() + * @see certsvc_instance_free() + * @see certsvc_string_new() + * @see certsvc_string_free() + * @see #CertStoreType + */ +int certsvc_pkcs12_import_from_file_to_store_ret_list(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString path, + CertSvcString password, + CertSvcString alias, + CertSvcStoreCertList **certList, + size_t *length); + /** * Delete the certificate with gname provided from cert-svc store. * diff --git a/src/vcore/api.cpp b/src/vcore/api.cpp index 1059c72..58fc882 100644 --- a/src/vcore/api.cpp +++ b/src/vcore/api.cpp @@ -891,10 +891,12 @@ err: CertStoreType storeType, CertSvcString path, CertSvcString pass, - CertSvcString pfxIdString) + CertSvcString pfxIdString, + CertSvcStoreCertList **certList, + size_t *length) { return pkcs12_import_from_file_to_store(storeType, path.privateHandler, pass.privateHandler, - pfxIdString.privateHandler); + pfxIdString.privateHandler, certList, length); } inline int pkcsGetAliasNameForCertInStore(CertStoreType storeType, @@ -1726,7 +1728,35 @@ int certsvc_pkcs12_import_from_file_to_store(CertSvcInstance instance, return CERTSVC_INVALID_STORE_TYPE; } - return impl(instance)->pkcsImportToStore(storeType, path, password, pfxIdString); + return impl(instance)->pkcsImportToStore(storeType, path, password, pfxIdString, + NULL, NULL); + } catch (...) { + LogError("Exception occured from pkcsImportToStore"); + return CERTSVC_FAIL; + } +} + +int certsvc_pkcs12_import_from_file_to_store_ret_list(CertSvcInstance instance, + CertStoreType storeType, + CertSvcString path, + CertSvcString password, + CertSvcString pfxIdString, + CertSvcStoreCertList **certList, + size_t *length) +{ + try { + if (certList == NULL || length == NULL) { + LogError("Wrong argument."); + return CERTSVC_WRONG_ARGUMENT; + } + + if (path.privateHandler == NULL || !impl(instance)->checkValidStoreType(storeType)) { + LogError("Invalid input parameter."); + return CERTSVC_INVALID_STORE_TYPE; + } + + return impl(instance)->pkcsImportToStore(storeType, path, password, pfxIdString, + certList, length); } catch (...) { LogError("Exception occured from pkcsImportToStore"); return CERTSVC_FAIL; diff --git a/src/vcore/pkcs12.cpp b/src/vcore/pkcs12.cpp index d2ec9d8..3e0cc70 100644 --- a/src/vcore/pkcs12.cpp +++ b/src/vcore/pkcs12.cpp @@ -98,6 +98,73 @@ inline CertStoreType nextStore(CertStoreType type) } } +CertSvcStoreCertList *createStoreListNode(const std::string &gname, const std::string &title, + CertStoreType storeType) +{ + CertSvcStoreCertList *node = (CertSvcStoreCertList *)malloc(sizeof(CertSvcStoreCertList)); + + if (node == NULL) + return NULL; + + node->gname = strdup(gname.c_str()); + node->title = strdup(title.c_str()); + node->status = ENABLED; + node->storeType = storeType; + node->next = NULL; + + if (node->gname == NULL || node->title == NULL) { + free(node->gname); + free(node->title); + free(node); + return NULL; + } + + return node; +} + +void destroyStoreList(CertSvcStoreCertList **certList, size_t *length) +{ + if (certList == NULL || length == NULL) { + return; + } + + CertSvcStoreCertList *list = *certList; + + while (list) { + CertSvcStoreCertList *next = list->next; + free(list->gname); + free(list->title); + free(list); + list = next; + } + + *length = 0; +} + +void addStoreListNode(CertSvcStoreCertList **list, CertSvcStoreCertList *node) +{ + node->next = *list; + *list = node; +} + +int appendStoreListNode(CertSvcStoreCertList **certList, size_t *length, + const std::string &gname, const std::string &alias, + CertStoreType storeType) +{ + if (certList == NULL || length == NULL) + return CERTSVC_SUCCESS; + + CertSvcStoreCertList *node = createStoreListNode(gname, alias, storeType); + if (node == NULL) { + return CERTSVC_BAD_ALLOC; + } + + addStoreListNode(certList, node); + (*length)++; + + return CERTSVC_SUCCESS; +} + std::string generateGname(void) { int generator; @@ -610,7 +677,9 @@ int insertToStore(CertStoreType storeTypes, const std::string &endCertName, const std::string &endCertBuffer, const std::vector &certChainName, - const std::vector &certChainBuffer) + const std::vector &certChainBuffer, + CertSvcStoreCertList **certList, + size_t *length) { size_t ncerts = certChainName.size(); @@ -634,6 +703,12 @@ int insertToStore(CertStoreType storeTypes, return result; } + int res = appendStoreListNode(certList, length, endCertName, alias, storeType); + if (res != CERTSVC_SUCCESS) { + LogError("Failed to append store list node."); + return result; + } + for (size_t i = 0; i < ncerts; i++) { if (i == ncerts - 1) result = installChainCert(storeType, certChainBuffer[i], certChainName[i], endCertName, @@ -646,6 +721,12 @@ int insertToStore(CertStoreType storeTypes, LogError("Failed to install the ca certificates. result : " << result); return result; } + + int res = appendStoreListNode(certList, length, certChainName[i], alias, storeType); + if (res != CERTSVC_SUCCESS) { + LogError("Failed to append store list node."); + return result; + } } } @@ -654,7 +735,7 @@ int insertToStore(CertStoreType storeTypes, } int insertToStorePEM(CertStoreType storeTypes, const std::string &path, const std::string &gname, - const std::string &alias) + const std::string &alias, CertSvcStoreCertList **certList, size_t *length) { std::string content = readFromFile(path); @@ -683,6 +764,13 @@ int insertToStorePEM(CertStoreType storeTypes, const std::string &path, const st return result; } + int res = appendStoreListNode(certList, length, gname, alias, storeType); + if (res != CERTSVC_SUCCESS) { + rollbackStore(storeTypes, gname); + LogError("Failed to append store list node."); + return result; + } + LogDebug("Success to install PEM/CRT to db store : " << storeType); } @@ -696,7 +784,9 @@ int insertToStorePEM(CertStoreType storeTypes, const std::string &path, const st int pkcs12_import_from_file_to_store(CertStoreType storeTypes, const char *_path, const char *_password, - const char *_alias) + const char *_alias, + CertSvcStoreCertList **certList, + size_t *length) { int result = 0; @@ -731,10 +821,12 @@ int pkcs12_import_from_file_to_store(CertStoreType storeTypes, if (strcasecmp(suffix.c_str(), ".pem") == 0 || strcasecmp(suffix.c_str(), ".crt") == 0) { std::string gnamePEM = generateGname(); - result = insertToStorePEM(storeTypes, path, gnamePEM, alias); + result = insertToStorePEM(storeTypes, path, gnamePEM, alias, certList, length); - if (result != CERTSVC_SUCCESS) + if (result != CERTSVC_SUCCESS) { + destroyStoreList(certList, length); LogError("Failed to install PEM/CRT file to store. gname : " << gnamePEM << " result : " << result); + } return result;; } @@ -806,10 +898,14 @@ int pkcs12_import_from_file_to_store(CertStoreType storeTypes, endCertName, endCertBuffer, certChainName, - certChainBuffer); + certChainBuffer, + certList, + length); - if (result != CERTSVC_SUCCESS) + if (result != CERTSVC_SUCCESS) { + destroyStoreList(certList, length); rollbackStore(storeTypes, endCertName); + } LogDebug("Success to import pkcs12 to store"); return result; diff --git a/src/vcore/pkcs12.h b/src/vcore/pkcs12.h index 89c1809..54df9a5 100644 --- a/src/vcore/pkcs12.h +++ b/src/vcore/pkcs12.h @@ -30,10 +30,16 @@ * @param[in] path Path to file. * @param[in] password Password for opening the file. * @param[in] alias Logical name for certificate bundle identification (can't be empty). + * @param[out] certList cert list in store returned in linked list. Free by + * certsvc_pkcs12_free_certificate_list_loaded_from_store() + * after use. Pass NULL if you don't want to return a list. + * @param[out] length length of output @a certList. Pass NULL if you don't + * want to return a list. * @return CERTSVC_SUCCESS, CERTSVC_FAIL, CERTSVC_DUPLICATED_ALIAS, CERTSVC_IO_ERROR, CERTSVC_WRONG_ARGUMENT, CERTSVC_BAD_ALLOC. */ int pkcs12_import_from_file_to_store(CertStoreType storeType, const char *path, - const char *password, const char *alias); + const char *password, const char *alias, CertSvcStoreCertList **certList, + size_t *length); /** * TO check if the p12/pfx file is protected by password or not. diff --git a/tests/pkcs12/new_test_cases.cpp b/tests/pkcs12/new_test_cases.cpp index 69ac7b7..6004125 100644 --- a/tests/pkcs12/new_test_cases.cpp +++ b/tests/pkcs12/new_test_cases.cpp @@ -952,3 +952,105 @@ RUNNER_TEST(CERTSVC_PKCS12_1028_certsvc_set_cert_to_disabled_and_get_status_for_ FREE_INSTANCE } +static void remove_certificates_from_store(CertSvcInstance &instance, CertStoreType storeType) +{ + int result; + size_t length = 0; + CertSvcStoreCertList *certList = NULL; + CertSvcStoreCertList *certListIter = NULL; + + result = certsvc_pkcs12_get_certificate_list_from_store(instance, storeType, DISABLED, &certList, + &length); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "Getting certificate list from system store failed"); + + certListIter = certList; + + while (certListIter) { + CertSvcString Gname = wrapper_certsvc_string_new(certListIter->gname); + + result = certsvc_pkcs12_delete_certificate_from_store(instance, storeType, Gname); + + certsvc_string_free(Gname); + certListIter = certListIter->next; + } +} + +size_t count_certificates_on_list(CertSvcStoreCertList *certList) +{ + size_t counter = 0; + + while (certList) { + counter++; + certList = certList->next; + } + + return counter; +} + +RUNNER_TEST(CERTSVC_PKCS12_1029_install_certs_from_p12_file_using_wifi_store_ret_list) +{ + int result; + CertSvcStoreCertList *certList = NULL; + size_t length = 0; + + CREATE_INSTANCE + + remove_certificates_from_store(instance, WIFI_STORE); + + CertSvcString Alias = wrapper_certsvc_string_new("P12-WifiUser-wifi-store"); + CertSvcString Path = wrapper_certsvc_string_new(TestData::UserP12WithPassPath.c_str()); + CertSvcString Pass = wrapper_certsvc_string_new(TestData::UserP12Pass.c_str()); + + result = certsvc_pkcs12_import_from_file_to_store_ret_list(instance, WIFI_STORE, Path, Pass, Alias, + &certList, &length); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "Importing P12 file to WIFI store failed."); + RUNNER_ASSERT_MSG(length == 3, "There should be 3 imported certificates"); + size_t count = count_certificates_on_list(certList); + RUNNER_ASSERT_MSG(length == count, "The length is different than number of elements on the list"); + + result = certsvc_pkcs12_free_certificate_list_loaded_from_store(instance, &certList); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "Freeing certificate list from system store failed"); + + remove_certificates_from_store(instance, WIFI_STORE); + + certsvc_string_free(Alias); + certsvc_string_free(Path); + certsvc_string_free(Pass); + + FREE_INSTANCE +} + +RUNNER_TEST(CERTSVC_PKCS12_1030_install_certs_from_pem_file_using_wifi_store_ret_list) +{ + int result; + CertSvcStoreCertList *certList = NULL; + size_t length = 0; + + CREATE_INSTANCE + + remove_certificates_from_store(instance, WIFI_STORE); + + CertSvcString PEMPath = wrapper_certsvc_string_new(TestData::ServerCertPemPath.c_str()); + CertSvcString PEMPass = wrapper_certsvc_string_new(NULL); + // alias has been taken from PEM file + CertSvcString PEMAlias = wrapper_certsvc_string_new("PEM-WifiUser-wifi-store"); + + result = certsvc_pkcs12_import_from_file_to_store_ret_list(instance, WIFI_STORE, PEMPath, PEMPass, PEMAlias, + &certList, &length); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "Importing PEM file to WIFI store failed."); + RUNNER_ASSERT_MSG(length == 1, "There should be 3 imported certificates"); + size_t count = count_certificates_on_list(certList); + RUNNER_ASSERT_MSG(length == count, "The length is different than number of elements on the list"); + + result = certsvc_pkcs12_free_certificate_list_loaded_from_store(instance, &certList); + RUNNER_ASSERT_MSG(result == CERTSVC_SUCCESS, "Freeing certificate list from system store failed"); + + remove_certificates_from_store(instance, WIFI_STORE); + + certsvc_string_free(PEMAlias); + certsvc_string_free(PEMPath); + certsvc_string_free(PEMPass); + + FREE_INSTANCE +} + -- 2.7.4