#pragma once
#include <windows.h>
#include <stdio.h>
#include <Wincrypt.h>
#include "argument.h"


#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define SHA1_DIGEST_SIZE 20 // in bytes


class CertUtils {
public:
static void PrintFileTimeToString(FILETIME ft);
static void SearchCertBySubject(Arguments args);
static void SearchCertByThumbprint(Arguments args);
static HCERTSTORE OpenCertStore();
static void CloseCertStore(HCERTSTORE hSystemStore);
static vector<PCCERT_CONTEXT> GetCertificates(HCERTSTORE hSystemStore, DWORD findType, const void* pvFindData, bool onlyFirstOne = false);
static void FreeCerts(vector<PCCERT_CONTEXT> certs);
static bool CheckCertProperty(PCCERT_CONTEXT cert, DWORD propId);
static void ScanCertProperty(PCCERT_CONTEXT pCertContext);
static void CheckCertProperty(Arguments args);
static void SetCertProperty(Arguments args);
static void RemoveCertProperty(Arguments args);
};


HCERTSTORE CertUtils::OpenCertStore()
{
    HCERTSTORE  hSystemStore;              // The system store handle.

    //-------------------------------------------------------------------
    // Open the certificate store to be searched.

    if (hSystemStore = CertOpenStore(
        CERT_STORE_PROV_SYSTEM,
        0,                      // Encoding type not needed 
                                // with this PROV.
        NULL,                   // Accept the default HCRYPTPROV. 
        CERT_SYSTEM_STORE_LOCAL_MACHINE, //;CERT_SYSTEM_STORE_CURRENT_USER, CERT_SYSTEM_STORE_LOCAL_MACHINE
        // Set the system store location in 
        // the registry.
        L"MY"))                 // Could have used other predefined 
                                // system stores
                                // including Trust, CA, or Root.
    {
        printf("Opened the MY system store. \n");
    }
    else
    {
        printf("Could not open the MY system store.\n");
        exit(1);
    }

    return hSystemStore;
}


void CertUtils::CloseCertStore(HCERTSTORE hSystemStore)
{
    if (hSystemStore)
        CertCloseStore(
            hSystemStore,
            CERT_CLOSE_STORE_CHECK_FLAG);
}

//findType: CERT_FIND_SUBJECT_STR, CERT_FIND_SHA1_HASH
vector<PCCERT_CONTEXT> CertUtils::GetCertificates(HCERTSTORE hSystemStore, DWORD findType, const void *pvFindData, bool onlyFirstOne)
{
    vector<PCCERT_CONTEXT> certs;

    PCCERT_CONTEXT  pDesiredCert = NULL;   // Set to NULL for the first 
                                           // call to
                                           // CertFindCertificateInStore.

    //-------------------------------------------------------------------
    // Get a certificate that has lpszCertSubject as its 
    // subject. 

    if (pDesiredCert = CertFindCertificateInStore(
        hSystemStore,
        MY_ENCODING_TYPE,           // Use X509_ASN_ENCODING.
        0,                          // No dwFlags needed. 
        findType,      // Find a certificate with a
                                    // thumbprint that matches the string
                                    // in the next parameter.
        pvFindData,           // The Unicode string to be found
                                    // in a certificate's subject.
        NULL))                      // NULL for the first call to the
                                    // function. In all subsequent
                                    // calls, it is the last pointer
                                    // returned by the function.
    {
        printf("The desired certificate was found. \n");
        PrintFileTimeToString(pDesiredCert->pCertInfo->NotAfter);
        ScanCertProperty(pDesiredCert);
        certs.push_back(CertDuplicateCertificateContext(pDesiredCert));
    }
    else
    {
        printf("Could not find the desired certificate.\n");
    }

    if (!onlyFirstOne)
    {
        while (pDesiredCert)
        {
            pDesiredCert = CertFindCertificateInStore(
                hSystemStore,
                MY_ENCODING_TYPE,           // Use X509_ASN_ENCODING.
                0,                          // No dwFlags needed. 
                findType,      // Find a certificate with a
                                            // thumbprint that matches the string
                                            // in the next parameter.
                pvFindData,           // The Unicode string to be found
                                            // in a certificate's subject.
                pDesiredCert);                      // NULL for the first call to the
                                            // function. In all subsequent
                                            // calls, it is the last pointer
                                            // returned by the function.
                                            // If NOT NULL, the CertFindCertificateInStore will also free the object

            if (pDesiredCert)
            {
                printf("The desired certificate was found. \n");
                PrintFileTimeToString(pDesiredCert->pCertInfo->NotAfter);

                ScanCertProperty(pDesiredCert);

                certs.push_back(CertDuplicateCertificateContext(pDesiredCert));
            }
        }
    }

    printf("In total found %d certs.\n", certs.size());

    if (pDesiredCert)
    {
        // Free the one since the certs only contains duplicated one.
        CertFreeCertificateContext(pDesiredCert);
    }

    return certs;
}

void CertUtils::FreeCerts(vector<PCCERT_CONTEXT> certs)
{
    for (PCCERT_CONTEXT cert : certs)
    {
        if (cert)
            CertFreeCertificateContext(cert);
    }
}

void CertUtils::SearchCertBySubject(Arguments args)
{
    std::wstring subjectStr = StringUtils::S2WS(args.GetValue("subject")); //L"xtest-superadmin.int.rdst-internal.net";
    LPCWSTR lpszCertSubject = subjectStr.c_str();
    //-------------------------------------------------------------------
    // Declare and initialize variables.
    HCERTSTORE  hSystemStore;              // The system store handle.
    hSystemStore = CertUtils::OpenCertStore(); // After OpenCertStore is called, then the store looks like is cached in memory, even a cert is removed from cert store, it could still be found with below CertFindCertificateInStore with the 'hSystemStore' returned here.


    //wcout << "Will sleep 20s" << std::endl;
    //Sleep(20000);


    //-------------------------------------------------------------------
    // Get a certificate that has lpszCertSubject as its 
    // subject. 
    vector<PCCERT_CONTEXT> certs = CertUtils::GetCertificates(hSystemStore, CERT_FIND_SUBJECT_STR, lpszCertSubject);

    //-------------------------------------------------------------------
    // Clean up. 
    FreeCerts(certs);

    CertUtils::CloseCertStore(hSystemStore);

} 
/*

D:\ex\C++\Crypt\Debug>Crypt.exe certsearch -subject=xtest-superadmin.int.rdst-internal.net
Function name: certsearch
Key=subject, Value=xtest-superadmin.int.rdst-internal.net
Got argument vaue 'xtest-superadmin.int.rdst-internal.net' for 'subject'
Opened the MY system store.
The desired certificate was found.
szLocalDateSaturday, March 19, 2022
szLocalTime11:51:37 AM
The desired certificate was found.
szLocalDateThursday, August 19, 2021
szLocalTime11:53:56 AM
The desired certificate was found.
szLocalDateSaturday, September 7, 2019
szLocalTime4:00:37 AM
Could not find the desired certificate.



After uninstall the 2nd cert:

D:\ex\C++\Crypt\Debug>Crypt.exe certsearch -subject=xtest-superadmin.int.rdst-internal.net
Function name: certsearch
Key=subject, Value=xtest-superadmin.int.rdst-internal.net
Got argument vaue 'xtest-superadmin.int.rdst-internal.net' for 'subject'
Opened the MY system store.
The desired certificate was found.
szLocalDateSaturday, March 19, 2022
szLocalTime11:51:37 AM
The desired certificate was found.
szLocalDateSaturday, September 7, 2019
szLocalTime4:00:37 AM
Could not find the desired certificate.



After re-install the 2nd cert, the output sequence still follow previous sequence. Looks like following NotBefore order, but not sure.

D:\ex\C++\Crypt\Debug>Crypt.exe certsearch -subject=xtest-superadmin.int.rdst-internal.net
Function name: certsearch
Key=subject, Value=xtest-superadmin.int.rdst-internal.net
Got argument vaue 'xtest-superadmin.int.rdst-internal.net' for 'subject'
Opened the MY system store.
The desired certificate was found.
szLocalDateSaturday, March 19, 2022
szLocalTime11:51:37 AM
The desired certificate was found.
szLocalDateThursday, August 19, 2021
szLocalTime11:53:56 AM
The desired certificate was found.
szLocalDateSaturday, September 7, 2019
szLocalTime4:00:37 AM
Could not find the desired certificate.
*/

void CertUtils::SearchCertByThumbprint(Arguments args)
{
    std::string thumbprintStr = args.GetValue("thumbprint");
    LPCSTR lpszCertThumbprint = thumbprintStr.c_str();

    CRYPT_HASH_BLOB hashBlob = { 0, nullptr };

    const void* findPara = nullptr;
    vector<BYTE> digest;
    StringUtils::Hex2Bytes(lpszCertThumbprint, digest);

    hashBlob.pbData = &digest[0];
    hashBlob.cbData = SHA1_DIGEST_SIZE;
    findPara = &hashBlob;

    //-------------------------------------------------------------------
    // Declare and initialize variables.
    HCERTSTORE  hSystemStore;              // The system store handle.
    hSystemStore = CertUtils::OpenCertStore();

    vector<PCCERT_CONTEXT> certs = CertUtils::GetCertificates(hSystemStore, CERT_FIND_SHA1_HASH, findPara);

    for (PCCERT_CONTEXT cert : certs)
    {
        CheckCertProperty(cert, CERT_SHA1_HASH_PROP_ID);
    }

    //-------------------------------------------------------------------
    // Clean up. 
    FreeCerts(certs);
    CertUtils::CloseCertStore(hSystemStore);

}


bool CertUtils::CheckCertProperty(PCCERT_CONTEXT cert, DWORD propId)
{
    bool exist = true;
    DWORD cbData;
    DWORD dwError;
    // if the latest has the renewal property then delete it
    if (!CertGetCertificateContextProperty(cert,
        propId,
        NULL,
        &cbData))
    {
        dwError = GetLastError();
        if (dwError == CRYPT_E_NOT_FOUND)
        {
            cout << "Not found property " << propId << std::endl;
            exist = false;
        }
        else
        {
            cout << "Failed to find property " << propId << ", last error: " << dwError << std::endl;
        }
    }
    else
    {
        BYTE* pbData = new (std::nothrow) BYTE[cbData];
        if (!CertGetCertificateContextProperty(cert,
            propId,
            pbData,
            &cbData))
        {
            cout << "Unable to get property " << propId << std::endl;
        }
        else
        {
            cout << "cbData: " << cbData << std::endl;
            vector<BYTE> hashBytes(pbData, pbData + cbData);
            std::string hashStr = StringUtils::Bytes2Hex(hashBytes);
            cout << "pbData in hex: " << hashStr << std::endl;
        }
    }

    return exist;
}

void CertUtils::ScanCertProperty(PCCERT_CONTEXT pCertContext)
{
    void* pvData;
    DWORD            cbData;
    CRYPT_KEY_PROV_INFO* pCryptKeyProvInfo;
    DWORD            dwPropId = 0;

    // In a loop, find all of the property IDs for the given certificate.
// The loop continues until the CertEnumCertificateContextProperties 
// returns 0.

    while (dwPropId = CertEnumCertificateContextProperties(
        pCertContext, // the context whose properties are to be listed.
        dwPropId))    // number of the last property found. Must be
                      // 0 to find the first property ID.
    {
        //--------------------------------------------------------------------
        // Each time through the loop, a property ID has been found.
        // Print the property number and information about the property.

        printf("Property # %d found->", dwPropId);
        switch (dwPropId)
        {
        case CERT_FRIENDLY_NAME_PROP_ID:
        {
            //--------------------------------------------------------------------
            //  Retrieve the actual display name certificate property.
            //  First, get the length of the property setting the
            //  pvData parameter to NULL to get a value for cbData
            //  to be used to allocate memory for the pvData buffer.
            printf("FRIENDLY_NAME_PROP_ID ");
            if (!(CertGetCertificateContextProperty(
                pCertContext,
                dwPropId,
                NULL,
                &cbData)))
            {
                MyHandleError("Call #1 to property length failed.");
            }

            //--------------------------------------------------------------------
            // The call succeeded. Use the size to allocate memory for the 
            // property.
            if (!(pvData = (void*)malloc(cbData)))
            {
                MyHandleError("Memory allocation failed.");
            }
            //--------------------------------------------------------------------
            // Allocation succeeded. Retrieve the property data.
            if (!(CertGetCertificateContextProperty(
                pCertContext,
                dwPropId,
                pvData,
                &cbData)))
            {
                MyHandleError("Call #2 getting the data failed.");
            }
            else
            {
                printf("\n  The display name is -> %s.", pvData);
                free(pvData);
            }
            break;
        }
        case CERT_SIGNATURE_HASH_PROP_ID:
        {
            printf("Signature hash ID. ");
            break;
        }
        case CERT_KEY_PROV_HANDLE_PROP_ID:
        {
            printf("KEY PROVE HANDLE.");
            break;
        }
        case CERT_KEY_PROV_INFO_PROP_ID:
        {
            printf("KEY PROV INFO PROP ID.");
            if (!(CertGetCertificateContextProperty(
                pCertContext,  // A pointer to the certificate
                               // where the property will be set.
                dwPropId,      // An identifier of the property to get. 
                               // In this case,
                               // CERT_KEY_PROV_INFO_PROP_ID
                NULL,          // NULL on the first call to get the
                               // length.
                &cbData)))     // The number of bytes that must be
                               // allocated for the structure.
            {
                MyHandleError("The property length was not retrieved.");
            }

            if (!(pCryptKeyProvInfo =
                (CRYPT_KEY_PROV_INFO*)malloc(cbData)))
            {
                MyHandleError("Error in allocation of memory.");
            }
            if (CertGetCertificateContextProperty(
                pCertContext,
                dwPropId,
                pCryptKeyProvInfo,
                &cbData))
            {
                printf("\n The current key container is %S.",
                    pCryptKeyProvInfo->pwszContainerName);
                free(pCryptKeyProvInfo);
            }
            else
            {
                free(pCryptKeyProvInfo);
                MyHandleError("The property was not retrieved.");
            }

            break;
        }
        case CERT_SHA1_HASH_PROP_ID:
        {
            printf("SHA1 HASH id.");
            break;
        }
        case CERT_MD5_HASH_PROP_ID:
        {
            printf("md5 hash id. ");
            break;
        }
        case CERT_KEY_CONTEXT_PROP_ID:
        {
            printf("KEY CONTEXT PROP id.");
            break;
        }
        case CERT_KEY_SPEC_PROP_ID:
        {
            printf("KEY SPEC PROP id.");
            break;
        }
        case CERT_ENHKEY_USAGE_PROP_ID:
        {
            printf("ENHKEY USAGE PROP id.");
            break;
        }
        case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
        {
            printf("NEXT UPDATE LOCATION PROP id.");
            break;
        }
        case CERT_PVK_FILE_PROP_ID:
        {
            printf("PVK FILE PROP id. ");
            break;
        }
        case CERT_DESCRIPTION_PROP_ID:
        {
            printf("DESCRIPTION PROP id. ");
            break;
        }
        case CERT_ACCESS_STATE_PROP_ID:
        {
            printf("ACCESS STATE PROP id. ");
            break;
        }
        case CERT_SMART_CARD_DATA_PROP_ID:
        {
            printf("SMAART_CARD DATA PROP id. ");
            break;
        }
        case CERT_EFS_PROP_ID:
        {
            printf("EFS PROP id. ");
            break;
        }
        case CERT_FORTEZZA_DATA_PROP_ID:
        {
            printf("FORTEZZA DATA PROP id.");
            break;
        }
        case CERT_ARCHIVED_PROP_ID:
        {
            printf("ARCHIVED PROP id.");
            break;
        }
        case CERT_KEY_IDENTIFIER_PROP_ID:
        {
            printf("KEY IDENTIFIER PROP id. ");
            break;
        }
        case CERT_AUTO_ENROLL_PROP_ID:
        {
            printf("AUTO ENROLL id. ");
            break;
        }
        }  // end switch
        printf("\n");
    } // end the inner while loop. This is the end of the display of
      // a single property of a single certificate.

    cout << "end loop" << std::endl;
}

void CertUtils::CheckCertProperty(Arguments args)
{
    std::string thumbprintStr = args.GetValue("thumbprint");
    std::string propertyIdStr = args.GetValue("propid");

    DWORD propId = StringUtils::DigitalStringToDWord(propertyIdStr);
    printf("propid=%ld\n", propId);

    LPCSTR lpszCertThumbprint = thumbprintStr.c_str();

    CRYPT_HASH_BLOB hashBlob = { 0, nullptr };

    const void* findPara = nullptr;
    vector<BYTE> digest;
    StringUtils::Hex2Bytes(lpszCertThumbprint, digest);

    hashBlob.pbData = &digest[0];
    hashBlob.cbData = SHA1_DIGEST_SIZE;
    findPara = &hashBlob;

    //-------------------------------------------------------------------
    // Declare and initialize variables.
    HCERTSTORE  hSystemStore;              // The system store handle.
    hSystemStore = CertUtils::OpenCertStore();

    vector<PCCERT_CONTEXT> certs = CertUtils::GetCertificates(hSystemStore, CERT_FIND_SHA1_HASH, findPara);
    printf("Cert count=%d\n", certs.size());

    PCCERT_CONTEXT cert = certs.front();

    CertUtils::CheckCertProperty(cert, propId);

    cout << "end" << std::endl;

    //-------------------------------------------------------------------
    // Clean up. 
    FreeCerts(certs);
    CertUtils::CloseCertStore(hSystemStore);

}


void CertUtils::SetCertProperty(Arguments args)
{
    std::string thumbprintStr = args.GetValue("thumbprint");
    std::string propertyIdStr = args.GetValue("propid");
    std::string hexValueStr = args.GetValue("hexvalue");

    DWORD propId = StringUtils::DigitalStringToDWord(propertyIdStr);
    printf("propid=%ld\n", propId);
    vector<BYTE> values;
    StringUtils::Hex2Bytes(hexValueStr, values);

    cout << "Value=" << StringUtils::Bytes2Hex(values) << std::endl;

    LPCSTR lpszCertThumbprint = thumbprintStr.c_str();

    CRYPT_HASH_BLOB hashBlob = { 0, nullptr };

    const void* findPara = nullptr;
    vector<BYTE> digest;
    StringUtils::Hex2Bytes(lpszCertThumbprint, digest);

    hashBlob.pbData = &digest[0];
    hashBlob.cbData = SHA1_DIGEST_SIZE;
    findPara = &hashBlob;

    //-------------------------------------------------------------------
    // Declare and initialize variables.
    HCERTSTORE  hSystemStore;              // The system store handle.
    hSystemStore = CertUtils::OpenCertStore();

    vector<PCCERT_CONTEXT> certs = CertUtils::GetCertificates(hSystemStore, CERT_FIND_SHA1_HASH, findPara);
    printf("Cert count=%d\n", certs.size());

    PCCERT_CONTEXT cert = certs.front();

    DWORD cbData;
    DWORD dwError;

    bool hasSet = CertUtils::CheckCertProperty(cert, propId);

    if (!hasSet)
    {
        cout << "cert does not have property " << propId << ", will set it to " << hexValueStr << std::endl;

        CRYPT_HASH_BLOB valueHashBlob = { 0, nullptr };
        valueHashBlob.pbData = &values[0];
        valueHashBlob.cbData = SHA1_DIGEST_SIZE;

        if (!CertSetCertificateContextProperty(
            cert,
            propId,
            NULL,
            &valueHashBlob))
        {
            dwError = GetLastError();
            cout << "Failed to set cert property " << propId << ", last error: " << dwError << std::endl;
        }
        else
        {
            cout << "Successfully set cert property " << propId << std::endl;
        }

    }

    cout << "end" << std::endl;

    //-------------------------------------------------------------------
    // Clean up. 
    FreeCerts(certs);
    CertUtils::CloseCertStore(hSystemStore);

} 



void CertUtils::RemoveCertProperty(Arguments args)
{
    std::string thumbprintStr = args.GetValue("thumbprint");
    std::string propertyIdStr = args.GetValue("propid");

    DWORD propId = StringUtils::DigitalStringToDWord(propertyIdStr);
    printf("propid=%ld\n", propId);

    LPCSTR lpszCertThumbprint = thumbprintStr.c_str();

    CRYPT_HASH_BLOB hashBlob = { 0, nullptr };

    const void* findPara = nullptr;
    vector<BYTE> digest;
    StringUtils::Hex2Bytes(lpszCertThumbprint, digest);

    hashBlob.pbData = &digest[0];
    hashBlob.cbData = SHA1_DIGEST_SIZE;
    findPara = &hashBlob;

    //-------------------------------------------------------------------
    // Declare and initialize variables.
    HCERTSTORE  hSystemStore;              // The system store handle.
    hSystemStore = CertUtils::OpenCertStore();

    vector<PCCERT_CONTEXT> certs = CertUtils::GetCertificates(hSystemStore, CERT_FIND_SHA1_HASH, findPara);
    printf("Cert count=%d\n", certs.size());

    PCCERT_CONTEXT cert = certs.front();

    DWORD cbData;
    DWORD dwError;

    bool hasSet = CertUtils::CheckCertProperty(cert, propId);

    if (hasSet)
    {
        cout << "cert has property " << propId << ", will remove it" << std::endl;

        if (!CertSetCertificateContextProperty(
            cert,
            propId,
            NULL,
            NULL))
        {
            dwError = GetLastError();
            cout << "Failed to remove cert property " << propId << ", last error: " << dwError << std::endl;
        }
        else
        {
            cout << "Successfully removed cert property " << propId << std::endl;
        }

    }

    cout << "end" << std::endl;

    //-------------------------------------------------------------------
    // Clean up. 
    FreeCerts(certs);
    CertUtils::CloseCertStore(hSystemStore);

} 


void CertUtils::PrintFileTimeToString(FILETIME ft)
{
    SYSTEMTIME st;
    wchar_t szLocalDate[256], szLocalTime[256];

    FileTimeToLocalFileTime(&ft, &ft);
    FileTimeToSystemTime(&ft, &st);
    GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL,
        szLocalDate, 255);
    GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255);
    wcout << "LocalDate" << szLocalDate << " LocalTime" << szLocalTime << std::endl;
}

 

Argument class:

#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
using namespace std;

class Argument {
public:
    Argument(char* arg);

    std::string Key;
    std::string Value;
};

class Arguments {
public:
    Arguments(int argc, char** argv);

    std::string GetValue(std::string key);

private:
    std::map<string, string> keyValueMap;
};


#include "argument.h"

Argument::Argument(char* arg)
{
    std::string argStr = std::string(arg);
    if (arg[0] != '-')
    {
        throw "Invalid argument '" + argStr + "', does not start with '-'";
    }

    int delimeterIndex = argStr.find_first_of('=');

    if (delimeterIndex < 0)
    {
        throw "Failed to parse argument: " + argStr + ", did not find delimeter";
    }

    Key = argStr.substr(1, delimeterIndex - 1);
    Value = argStr.substr(delimeterIndex + 1);

    std::cout << "Key=" << Key << ", Value=" << Value << std::endl;
}

Arguments::Arguments(int argc, char** argv)
{
    for (int i = 0; i < argc; ++i)
    {
        char* argStr = argv[i];
        Argument arg = Argument(argStr);
        std::string key = std::string(arg.Key);
        std::transform(key.begin(), key.end(), key.begin(), ::tolower);

        if (keyValueMap.find(key) != keyValueMap.end())
        {
            throw "Duplicated argument for " + key;
        }

        keyValueMap.insert(pair<string, string>(key, arg.Value));
    }
}

std::string Arguments::GetValue(std::string key)
{
    std::string lowKey = std::string(key);
    std::transform(lowKey.begin(), lowKey.end(), lowKey.begin(), ::tolower);

    auto npos = keyValueMap.find(key);
    if (npos == keyValueMap.end())
    {
        throw "Not found key '" + lowKey + "' in arguments.";
    }
    else
    {
        std::cout << "Got argument vaue '" << npos->second << "' for '" << key << "'" << std::endl;
        return npos->second;
    }
}

 

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        throw "Please input the function name";
    }

    std::string funcName = argv[1];
    std::cout << "Function name: " << funcName << std::endl;
    std::transform(funcName.begin(), funcName.end(), funcName.begin(), ::tolower);

    Arguments arguments = Arguments(argc - 2, argv + 2);

    if (funcName.compare("/?") == 0 || funcName.compare("help") == 0)
    {
        ShowHelp();
    }else if(funcName.compare("certsearchsubject") == 0)
    {
        CertUtils::SearchCertBySubject(arguments);
    }
    else if (funcName.compare("certsearchthumbprint") == 0)
    {
        CertUtils::SearchCertByThumbprint(arguments);
    }
    else if (funcName.compare("certcheckprop") == 0)
    {
        CertUtils::CheckCertProperty(arguments);
    }
    else if (funcName.compare("certsetprop") == 0)
    {
        CertUtils::SetCertProperty(arguments);
    }
    else if (funcName.compare("certremoveprop") == 0)
    {
        CertUtils::RemoveCertProperty(arguments);
    }
    else
    {
        throw "The function name '" + funcName + "' is not supported.";
    }

    return 0;
}


void ShowHelp()
{
    std::vector<std::string> SupportedFuncNames;
    SupportedFuncNames.push_back("test");
    SupportedFuncNames.push_back("h2b/hex2base64");
    SupportedFuncNames.push_back("b2h/base642hex");
    SupportedFuncNames.push_back("encrypt");
    SupportedFuncNames.push_back("decrypt");
    SupportedFuncNames.push_back("certencrypt");
    SupportedFuncNames.push_back("certdecrypt");
    SupportedFuncNames.push_back("certsearch");

    std::cout << "Support commands:" << std::endl;
    for (auto iter = SupportedFuncNames.begin(); iter != SupportedFuncNames.end(); ++iter)
    {
        std::cout << "\t" << *iter << std::endl;
    }
}