gcontini
2019-10-19 8bbef2865455754425a84b86680a89bff8aa7691
issue #64 , issue #56 (part)

Code review and refactoring:
Incompatible api changes (removed possibility to specify environment
variable name)
Part of issue #56 License retrieval has been made more flexible. License
verification is still waiting
issue #64 Add possibility to read the full license content from an
environment variable.
44个文件已修改
2个文件已添加
2384 ■■■■■ 已修改文件
.gitignore 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CONTRIBUTING.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
example/example.cpp 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/CMakeLists.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/LicenseReader.cpp 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/LicenseReader.hpp 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/api/datatypes.h 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/api/license++.h 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/CMakeLists.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/EventRegistry.cpp 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/EventRegistry.h 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/FileUtils.cpp 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/FileUtils.hpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/StringUtils.cpp 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/StringUtils.h 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/base64.c 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/base64.h 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/license++.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ApplicationFolder.cpp 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ApplicationFolder.hpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarData.cpp 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarData.hpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarLocation.cpp 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarLocation.hpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ExternalDefinition.cpp 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ExternalDefinition.hpp 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/LocatorFactory.cpp 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/LocatorFactory.hpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/LocatorStrategy.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/LocatorStrategy.hpp 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/os.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tools/base_lib/win/CryptoHelperWindows.cpp 788 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tools/base_lib/win/CryptoHelperWindows.h 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tools/license-generator/CMakeLists.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tools/license-generator/license-generator.cpp 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tools/license-generator/license-generator.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/CMakeLists.txt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/date_test.cpp 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/hijiaking_test.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/standard-license_test.cpp 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/volid_test.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/CMakeLists.txt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/EventRegistry_test.cpp 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/LicenseLocator_test.cpp 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/LicenseReader_test.cpp 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -7,6 +7,9 @@
*.so
*.dylib
#Visual studio files
.vs
# Compiled Static libraries
*.lai
*.la
CONTRIBUTING.md
@@ -18,7 +18,8 @@
* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how are you using Open License Manager. 
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or licenses, which can cause the bug. If you're providing code snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). The best way to report a bug is to **design a test** to demonstrate it.
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or licenses, which can cause the bug. If you're providing code snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Provide a boost unit test to demonstrate the bug**. The best way to report a bug, and to have it fixed **forever** is to design a test to demonstrate it.
* **If you're reporting that Open License Manager crashed**, include a crash dump and the associated message. 
* **Label the issue as bug.**
@@ -79,8 +80,8 @@
##### Don't
 * Don't reformat the code following your personal likes, it introduce a lot of "noise" and makes very hard to merge. 
 * Very large pull requests with few comments, no corresponding issue will probably be rejected.
    * We understand that the project is still in a very alpha stage and a rearrangement is needed, however we would like to discuss it with you before we take project changing decision.
    * We can't break current functionality, user established habits without documenting the change.
 * Very large pull requests with few comments, no corresponding issue explaining what's it about will probably be rejected.
    * We understand that the project is still in a very alpha stage and a rearrangement is needed, however we would like to discuss it with you before we take project changing decision. Please contact the project maintainer at `contini.mailing[AT]gmail.com` if you have time and plan to do a large contribution.
    * Even it it's in alpha stage it's used ( _by some really courageous people!_ ) in production. We can't break current functionality, user established habits without documenting the change.
  
README.md
@@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/open-license-manager/open-license-manager.svg?branch=develop)](https://travis-ci.org/open-license-manager/open-license-manager)
[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges)[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
A copy protection, licensing software written in C/C++ for Windows and Linux.
A copy protection, licensing software written in C++ for Windows and Linux (with a simple C api for use in C projects).
It allows to protect the software you develop from unauthorized copies,
limit the usage in time, to a specific set of machines, or prevent the usage in 
example/example.cpp
@@ -2,55 +2,46 @@
#include <map>
#include "api/license++.h"
#include "pc-identifiers.h"
#include "ini/SimpleIni.h"
using namespace std;
int main(int argc, char *argv[])
{
    map<EVENT_TYPE, string> stringByEventType;
    stringByEventType[LICENSE_OK                      ] = "OK ";
    stringByEventType[LICENSE_FILE_NOT_FOUND          ] = "license file not found ";
    stringByEventType[LICENSE_SERVER_NOT_FOUND        ] = "license server can't be contacted ";
    stringByEventType[ENVIRONMENT_VARIABLE_NOT_DEFINED] = "environment variable not defined ";
    stringByEventType[FILE_FORMAT_NOT_RECOGNIZED      ] = "license file has invalid format (not .ini file) ";
    stringByEventType[LICENSE_MALFORMED               ] = "some mandatory field are missing, or data can't be fully read. ";
    stringByEventType[PRODUCT_NOT_LICENSED            ] = "this product was not licensed ";
    stringByEventType[PRODUCT_EXPIRED                 ] = "license expired ";
    stringByEventType[LICENSE_CORRUPTED               ] = "license signature didn't match with current license ";
    stringByEventType[IDENTIFIERS_MISMATCH            ] = "Calculated identifier and the one provided in license didn't match";
    stringByEventType[LICENSE_FILE_FOUND              ] = "license file not found ";
    stringByEventType[LICENSE_VERIFIED                ] = "license verified ";
    const string licLocation("example.lic");
    LicenseInfo licenseInfo;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    EVENT_TYPE result = acquire_license("example", licenseLocation, &licenseInfo);
    PcSignature signature;
    FUNCTION_RETURN generate_ok = generate_user_pc_signature(signature, DEFAULT);
int main(int argc, char *argv[]) {
    map<EVENT_TYPE, string> stringByEventType;
    stringByEventType[LICENSE_OK] = "OK ";
    stringByEventType[LICENSE_FILE_NOT_FOUND] = "license file not found ";
    stringByEventType[LICENSE_SERVER_NOT_FOUND] = "license server can't be contacted ";
    stringByEventType[ENVIRONMENT_VARIABLE_NOT_DEFINED] = "environment variable not defined ";
    stringByEventType[FILE_FORMAT_NOT_RECOGNIZED] = "license file has invalid format (not .ini file) ";
    stringByEventType[LICENSE_MALFORMED] = "some mandatory field are missing, or data can't be fully read. ";
    stringByEventType[PRODUCT_NOT_LICENSED] = "this product was not licensed ";
    stringByEventType[PRODUCT_EXPIRED] = "license expired ";
    stringByEventType[LICENSE_CORRUPTED] = "license signature didn't match with current license ";
    stringByEventType[IDENTIFIERS_MISMATCH] = "Calculated identifier and the one provided in license didn't match";
    if (result == LICENSE_OK && licenseInfo.linked_to_pc) {
        CSimpleIniA ini;
        SI_Error rc = ini.LoadFile(licLocation.c_str());
        string IDinLicense = ini.GetValue("example", "client_signature", "");
        if (IDinLicense == "") {
            cout << "No client signature in license file, generate license with -s <id>";
    LicenseInfo licenseInfo;
    EVENT_TYPE result = acquire_license("example", nullptr, &licenseInfo);
    if (result == LICENSE_OK) {
        //for this example we want to link the license to the execution hardware.
        if (licenseInfo.linked_to_pc) {
            cout
                    << "No client signature in license file, generate license with -s <id>";
            result = IDENTIFIERS_MISMATCH;
        } else if (IDinLicense != signature) {
            result = IDENTIFIERS_MISMATCH;
        } else {
            cout << "license OK" << endl;
        }
    }
    if (result != LICENSE_OK) {
        cout << "license ERROR :" << endl;
        cout << "    " << stringByEventType[result].c_str() << endl;
        if (result == IDENTIFIERS_MISMATCH) {
            PcSignature signature;
            FUNCTION_RETURN generate_ok = generate_user_pc_signature(signature,
                    DEFAULT);
            cout << "the pc signature is :" << endl;
            cout << "    " << signature << endl;
        }
    }
    if (result != LICENSE_OK) {
        cout << "license ERROR :" << endl;
        cout << "    " << stringByEventType[result].c_str() << endl;
        cout << "the pc signature is :" << endl;
        cout << "    " << signature << endl;
    }
    else
        cout << "license OK" << endl;
    return result;
}
src/library/CMakeLists.txt
@@ -15,6 +15,7 @@
     ini
     locators
     os
     base
)
install(TARGETS licensecc_static ARCHIVE DESTINATION lib)
src/library/LicenseReader.cpp
@@ -52,35 +52,42 @@
        extra_data(extra_data) {
}
EventRegistry FullLicenseInfo::validate(int sw_version) {
    EventRegistry er;
bool FullLicenseInfo::validate(int sw_version,
        EventRegistry &eventRegistryOut) {
    os_initialize();
    const FUNCTION_RETURN sigVer = verifySignature(printForSign().c_str(),
            license_signature.c_str());
    const bool sigVerified = sigVer == FUNC_RET_OK;
    if (sigVerified) {
        er.addEvent(LICENSE_VERIFIED, SVRT_INFO);
    bool is_valid = (sigVer == FUNC_RET_OK);
    if (is_valid) {
        eventRegistryOut.addEvent(SIGNATURE_VERIFIED, source);
    } else {
        er.addEvent(LICENSE_CORRUPTED, SVRT_ERROR);
        eventRegistryOut.addEvent(LICENSE_CORRUPTED, source);
    }
    if (has_expiry) {
        cout<<source<<endl;
        const time_t now = time(nullptr);
        if (expires_on() < now) {
            er.addEvent(PRODUCT_EXPIRED, SVRT_ERROR, "");
/*
            eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
                    string("Expired on: " + this->to_date).c_str());*/
            eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),nullptr);
            is_valid = false;
        }
        if (valid_from() > now) {
            er.addEvent(PRODUCT_EXPIRED, SVRT_ERROR);
            /*eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
                    string("Valid from " + this->from_date).c_str());*/
            eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),nullptr);
            is_valid = false;
        }
    }
    if (has_client_sig) {
        PcSignature str_code;
        strncpy(str_code, client_signature.c_str(), sizeof(str_code) - 1);
        const EVENT_TYPE event = validate_pc_signature(str_code);
        if (event != LICENSE_OK) {
            er.addEvent(event, SVRT_ERROR);
        }
        eventRegistryOut.addEvent(event, source);
        is_valid = is_valid && (event == LICENSE_OK);
    }
    return er;
    return is_valid;
}
void FullLicenseInfo::toLicenseInfo(LicenseInfo *license) const {
@@ -102,7 +109,7 @@
    }
}
LicenseReader::LicenseReader(const LicenseLocation &licenseLocation) :
LicenseReader::LicenseReader(const LicenseLocation* licenseLocation) :
        licenseLocation(licenseLocation) {
}
@@ -110,48 +117,39 @@
        vector<FullLicenseInfo> &licenseInfoOut) {
    vector<string> diskFiles;
    vector<unique_ptr<locate::LocatorStrategy>> locator_strategies;
    FUNCTION_RETURN ret = locate::LocatorFactory::getActiveStrategies(
            locator_strategies, licenseLocation.licenseFileLocation);
    FUNCTION_RETURN ret = locate::LocatorFactory::get_active_strategies(
            locator_strategies, licenseLocation);
    EventRegistry eventRegistry;
    if (ret != FUNC_RET_OK) {
        eventRegistry.addError(LICENSE_FILE_NOT_FOUND);
        eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND);
        eventRegistry.turnWarningsIntoErrors();
        return eventRegistry;
    }
    if (!eventRegistry.isGood()) {
        return eventRegistry;
    }
    bool atLeastOneFileFound = false;
    bool atLeastOneFileRecognized = false;
    bool atLeastOneProductLicensed = false;
    bool atLeastOneLicenseComplete = false;
    for (unique_ptr<locate::LocatorStrategy>& locator : locator_strategies) {
        vector<string> licenseLocations = locator->licenseLocations(
    for (unique_ptr<locate::LocatorStrategy> &locator : locator_strategies) {
        vector<string> licenseLocations = locator->license_locations(
                eventRegistry);
        if (licenseLocations.size() == 0) {
            continue;
        }
        atLeastOneFileFound = true;
        CSimpleIniA ini;
        for (auto it = licenseLocations.begin(); it != licenseLocations.end();
                it++) {
            ini.Reset();
            string license = locator->retrieveLicense((*it).c_str());
            string license = locator->retrieve_license_content((*it).c_str());
            const SI_Error rc = ini.LoadData(license.c_str(), license.size());
            if (rc < 0) {
                eventRegistry.addEvent(FILE_FORMAT_NOT_RECOGNIZED, SVRT_WARN,
                        *it);
                eventRegistry.addEvent(FILE_FORMAT_NOT_RECOGNIZED,     *it);
                continue;
            } else {
                atLeastOneFileRecognized = true;
            }
            const char *productNamePtr = product.c_str();
            const int sectionSize = ini.GetSectionSize(productNamePtr);
            if (sectionSize <= 0) {
                eventRegistry.addEvent(PRODUCT_NOT_LICENSED, SVRT_WARN, *it);
                eventRegistry.addEvent(PRODUCT_NOT_LICENSED, *it);
                continue;
            } else {
                atLeastOneProductLicensed = true;
                eventRegistry.addEvent(PRODUCT_FOUND,     *it);
            }
            /*
             *  sw_version_from = (optional int)
@@ -193,19 +191,12 @@
                licenseInfoOut.push_back(licInfo);
                atLeastOneLicenseComplete = true;
            } else {
                eventRegistry.addEvent(LICENSE_MALFORMED, SVRT_WARN, *it);
                eventRegistry.addEvent(LICENSE_MALFORMED, *it);
            }
        }
    }
    if (!atLeastOneFileFound) {
        eventRegistry.turnEventIntoError(ENVIRONMENT_VARIABLE_NOT_DEFINED);
        eventRegistry.turnEventIntoError(LICENSE_FILE_NOT_FOUND);
    } else if (!atLeastOneFileRecognized) {
        eventRegistry.turnEventIntoError(FILE_FORMAT_NOT_RECOGNIZED);
    } else if (!atLeastOneProductLicensed) {
        eventRegistry.turnEventIntoError(PRODUCT_NOT_LICENSED);
    } else    if (!atLeastOneLicenseComplete) {
        eventRegistry.turnEventIntoError(LICENSE_MALFORMED);
    if (!atLeastOneLicenseComplete) {
        eventRegistry.turnWarningsIntoErrors();
    }
    return eventRegistry;
}
src/library/LicenseReader.hpp
@@ -2,55 +2,53 @@
 * LicenseReader.h
 *
 *  Created on: Mar 30, 2014
 *
 *
 */
#ifndef LICENSEREADER_H_
#define LICENSEREADER_H_
#include <string>
#include <ctime>
#define SI_SUPPORT_IOSTREAMS
#include "api/datatypes.h"
#include "base/EventRegistry.h"
#include "os/os.h"
#include "locate/LocatorStrategy.hpp"
#define SI_SUPPORT_IOSTREAMS
#include "ini/SimpleIni.h"
#include <string>
#include <ctime>
namespace license {
using namespace std;
namespace license {
class FullLicenseInfo {
public:
    string source;
    string product;
    string license_signature;
    std::string source;
    std::string product;
    std::string license_signature;
    int license_version;
    string from_date;
    string to_date;
    std::string from_date;
    std::string to_date;
    bool has_expiry;
    unsigned int from_sw_version;
    unsigned int to_sw_version;
    bool has_versions;
    string client_signature;
    std::string client_signature;
    bool has_client_sig;
    string extra_data;
    std::string extra_data;
    static const char* UNUSED_TIME;
    static const unsigned int UNUSED_SOFTWARE_VERSION = 0;
    FullLicenseInfo(const string& source, const string& product,
            const string& license_signature, int licenseVersion,
            string from_date = UNUSED_TIME,
            string to_date = UNUSED_TIME, //
            const string& client_signature = "", //
    FullLicenseInfo(const std::string& source, const std::string& product,
            const std::string& license_signature, int licenseVersion,
            std::string from_date = UNUSED_TIME,
            std::string to_date = UNUSED_TIME, //
            const std::string& client_signature = "", //
            unsigned int from_sw_version = UNUSED_SOFTWARE_VERSION,
            unsigned int to_sw_version = UNUSED_SOFTWARE_VERSION,
            const string& extra_data = "");
    string printForSign() const;
    void printAsIni(ostream & a_ostream) const;
            const std::string& extra_data = "");
    std::string printForSign() const;
    void printAsIni(std::ostream & a_ostream) const;
    void toLicenseInfo(LicenseInfo* license) const;
    EventRegistry validate(int sw_version);
    bool validate(int sw_version, EventRegistry& eventRegistryOut);
    time_t expires_on() const;
    time_t valid_from() const;
};
@@ -67,19 +65,19 @@
 *  sw_version_to = (optional int)
 *  from_date = YYYY-MM-DD (optional)
 *  to_date  = YYYY-MM-DD (optional)
 *  client_signature = XXXXXXXX (optional string 16)
 *  client_signature = XXXXXXXX (optional std::string 16)
 *  license_signature = XXXXXXXXXX (mandatory, 1024)
 *  application_data = xxxxxxxxx (optional string 16)
 *  application_data = xxxxxxxxx (optional std::string 16)
 *    license_version = 100 (mandatory int)
 *  </pre>
 */
class LicenseReader {
private:
    const LicenseLocation licenseLocation;
    const LicenseLocation* licenseLocation;
public:
    LicenseReader(const LicenseLocation& licenseLocation);
    EventRegistry readLicenses(const string &product,
            vector<FullLicenseInfo>& licenseInfoOut);
    LicenseReader(const LicenseLocation* licenseLocation);
    EventRegistry readLicenses(const std::string &product,
            std::vector<FullLicenseInfo>& licenseInfoOut);
    virtual ~LicenseReader();
};
}
src/library/api/datatypes.h
@@ -13,13 +13,18 @@
#ifdef __unix__
#define DllExport
#ifndef MAX_PATH
    #define MAX_PATH 1024
#endif
#else
#include <windows.h>
#define DllExport  __declspec( dllexport )
#endif
#define PC_IDENTIFIER_SIZE 18
#define PROPRIETARY_DATA_SIZE 16
#define AUDIT_EVENT_NUM 5
#define LICENESE_INT_VERSION 110
#define LICENSEPP_VERSION "1.1.0"
@@ -36,8 +41,10 @@
    LICENSE_CORRUPTED = 8,        //License signature didn't match with current license
    IDENTIFIERS_MISMATCH = 9,   //Calculated identifier and the one provided in license didn't match
    LICENSE_FILE_FOUND = 100,
    LICENSE_VERIFIED = 101
    LICENSE_SPECIFIED = 100,    //license location was specified
    LICENSE_FOUND = 101,         //License file has been found or license data has been located
    PRODUCT_FOUND = 102,        //License has been loaded and the declared product has been found
    SIGNATURE_VERIFIED = 103
} EVENT_TYPE;
@@ -52,23 +59,40 @@
typedef struct {
    SEVERITY severity;
    EVENT_TYPE event_type;
    char param1[256];
    /**
     * License file name or location where the license is stored.
     */
    char license_reference[MAX_PATH];
    char param2[256];
} AuditEvent;
/**
 * This structure contains informations on the raw license data. Software authors
 * can specify the location of the license file or its full content.
 *
 * Can be NULL, in this case OpenLicenseManager will try to figure out the
 * license file location on its own.
 */
typedef struct {
    /**
     * A list of absolute path separated by ';' containing the eventual location
     * of the license files. Can be NULL.
     */
    const char *licenseFileLocation;
    const char *environmentVariableName;
    bool openFileNearModule;
    /**
     * The application can provide the full license content through this string.
     * It can be both in encoded form (base64) or in plain. It's optional.
     */
    const char *licenseData;
} LicenseLocation;
typedef struct {
    /**
     * Detailed reason of success/failure. Reasons for a failure can be
     * multiple (for instance, license expired and signature not verified).
     * Only the last 5 are reported.
     * Only the last AUDIT_EVENT_NUM are reported.
     */
    AuditEvent status[5];
    AuditEvent status[AUDIT_EVENT_NUM];
    /**
     * Eventual expiration date of the software,
     * can be '\0' if the software don't expire
src/library/api/license++.h
@@ -3,22 +3,9 @@
/*
 * This include file is the public api di License++
 * You should include this file if your software don't plan to use
 * the part of the library dealing with features.
 * Otherwise licensepp-features.h should be included.
 */
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __unix__
#define DllExport
#ifndef MAX_PATH
    #define MAX_PATH 1024
#endif
#else
#include <windows.h>
#define DllExport  __declspec( dllexport )
#endif
#include "datatypes.h"
@@ -53,7 +40,7 @@
 */
EVENT_TYPE acquire_license(const char * productName,
        LicenseLocation licenseLocation, LicenseInfo* license);
        const LicenseLocation* licenseLocation, LicenseInfo* license);
/**
 * Do nothing for now, useful for network licenses.
@@ -61,7 +48,7 @@
 * license.
 */
EVENT_TYPE confirm_license(char * featureName,
        LicenseLocation licenseLocation);
        LicenseLocation* licenseLocation);
/**
 * Do nothing for now, useful for network licenses.
 */
src/library/base/CMakeLists.txt
@@ -3,6 +3,7 @@
    StringUtils.cpp
    FileUtils.cpp
    logger.c
    base64.c
)
add_dependencies( base public_key )
src/library/base/EventRegistry.cpp
@@ -2,106 +2,151 @@
 * EventRegistry.cpp
 *
 *  Created on: Mar 30, 2014
 *
 *
 */
#include "EventRegistry.h"
#include <cstddef>
#include <string.h>
#include <algorithm>
#include <map>
#include <iostream>
#include "EventRegistry.h"
#define LIC_ID_NOT_DEFINED "UNDEF"
namespace license {
using namespace std;
const map<EVENT_TYPE, int> PROGRESS_BY_EVENT_TYPE = { { LICENSE_SPECIFIED, 0 },
        { LICENSE_FOUND, 1 }, { PRODUCT_FOUND, 2 }, { SIGNATURE_VERIFIED, 3 }, {
                LICENSE_OK, 4 } };
EventRegistry::EventRegistry() {
    current_validation_step = -1;
}
EventRegistry& operator<<(EventRegistry& eventRegistry,
        AuditEvent& securityEvent) {
EventRegistry& operator<<(EventRegistry &eventRegistry,
        AuditEvent &securityEvent) {
    eventRegistry.logs.push_back(securityEvent);
    return eventRegistry;
}
EventRegistry& operator<<(EventRegistry& eventRegistry1,
        EventRegistry& otherRegistry) {
EventRegistry& operator<<(EventRegistry &eventRegistry1,
        EventRegistry &otherRegistry) {
    eventRegistry1.append(otherRegistry);
    return eventRegistry1;
}
void EventRegistry::append(const EventRegistry& eventRegistry) {
ostream& operator<<(std::ostream &out, const EventRegistry &er) {
    out << string("EventReg[step:") << er.current_validation_step
            << ",events:{";
    for (auto &it : er.logs) {
        out << "[ev:" << it.event_type << ",sev:" << it.severity << "ref:"
                << it.license_reference << "]";
    }
    out << "]";
    return out;
}
void EventRegistry::append(const EventRegistry &eventRegistry) {
    logs.insert(logs.end(), eventRegistry.logs.begin(),
            eventRegistry.logs.end());
}
void EventRegistry::turnLastEventIntoError() {
    if (logs.size() > 0) {
        logs.back().severity = SVRT_ERROR;
AuditEvent const* EventRegistry::getLastFailure() const {
    const AuditEvent *result = nullptr;
    if (logs.size() == 0) {
        return result;
    }
    //try to find a failure between the licenses who progressed the most
    if (mostAdvancedLogIdx_by_LicenseId.size() > 0) {
        for (auto const &mostAdvLogIter : mostAdvancedLogIdx_by_LicenseId) {
            const AuditEvent &currentLog = logs[mostAdvLogIter.second];
            if (currentLog.severity == SVRT_ERROR) {
                result = &(currentLog);
                break;
            }
        }
    }
    if (result == nullptr) {
        auto it = logs.end();
        do {
            --it;
            if (it->severity == SVRT_ERROR) {
                result = &(*it);
                break;
            }
        } while (it != logs.begin());
    }
    return result;
}
void EventRegistry::addEvent(EVENT_TYPE event,
        const std::string &licenseLocationId) {
    addEvent(event, licenseLocationId.c_str(), nullptr);
}
void EventRegistry::addEvent(EVENT_TYPE event, const char *licenseLocationId,
        const char *info) {
    AuditEvent audit;
    auto eventIterator = PROGRESS_BY_EVENT_TYPE.find(event);
    bool successEvent = (eventIterator != PROGRESS_BY_EVENT_TYPE.end());
    audit.severity = successEvent ? SVRT_INFO : SVRT_WARN;
    audit.event_type = event;
    if (licenseLocationId == nullptr) {
        strcpy(audit.license_reference, LIC_ID_NOT_DEFINED);
    } else {
        strncpy(audit.license_reference, licenseLocationId, MAX_PATH);
    }
    if (info == nullptr) {
        audit.param2[0] = '\0';
    } else {
        strncpy(audit.param2, info, 255);
    }
    logs.push_back(audit);
//udpate the status of the log
    if (successEvent) {
        int step = eventIterator->second;
        if (step > current_validation_step) {
            mostAdvancedLogIdx_by_LicenseId.clear();
            current_validation_step = step;
        }
        if (step == current_validation_step) {
            mostAdvancedLogIdx_by_LicenseId[audit.license_reference] =
                    logs.size() - 1;
        }
    } else if (mostAdvancedLogIdx_by_LicenseId.find(audit.license_reference)
            != mostAdvancedLogIdx_by_LicenseId.end()) {
        mostAdvancedLogIdx_by_LicenseId[audit.license_reference] = logs.size()
                - 1;
    }
}
bool EventRegistry::turnEventIntoError(EVENT_TYPE event) {
bool EventRegistry::turnWarningsIntoErrors() {
    bool eventFound = false;
    for (auto it = logs.begin(); it != logs.end(); ++it) {
        if (it->event_type == event) {
            it->severity = SVRT_ERROR;
            eventFound = true;
    if (mostAdvancedLogIdx_by_LicenseId.size() > 0) {
        for (auto const &mostAdvLogIter : mostAdvancedLogIdx_by_LicenseId) {
            AuditEvent &currentLog = logs[mostAdvLogIter.second];
            if (currentLog.severity == SVRT_WARN
                    || currentLog.severity == SVRT_ERROR) {
                currentLog.severity = SVRT_ERROR;
                eventFound = true;
            }
        }
    }
    if (!eventFound) {
        for (auto it = logs.begin(); it != logs.end(); ++it) {
            if (it->severity == SVRT_WARN) {
                it->severity = SVRT_ERROR;
                eventFound = true;
            }
        }
    }
    return eventFound;
}
AuditEvent const * EventRegistry::getLastFailure() const {
    const AuditEvent* result = nullptr;
    if (logs.size() == 0) {
        return result;
    }
    auto it = logs.end();
    do {
        --it;
        if (it->severity == SVRT_ERROR) {
            result = &(*it);
            break;
        }
    } while (it != logs.begin());
    return result;
}
bool EventRegistry::isGood() const {
    bool isGood = true;
    for (auto it = logs.begin(); it != logs.end(); ++it) {
        if (it->severity == SVRT_ERROR) {
            isGood = false;
            break;
        }
    }
    return isGood;
}
void EventRegistry::addError(EVENT_TYPE event) {
    this->addEvent(event, SVRT_ERROR);
}
void EventRegistry::addEvent(EVENT_TYPE event, SEVERITY severity) {
    AuditEvent audit;
    audit.severity = severity;
    audit.event_type = event;
    audit.param1[0] = '\0';
    audit.param2[0] = '\0';
    logs.push_back(audit);
}
void EventRegistry::addEvent(EVENT_TYPE event, SEVERITY severity,
        const string& eventParameter) {
    AuditEvent audit;
    audit.severity = severity;
    audit.event_type = event;
    strncpy(audit.param1, eventParameter.c_str(), 255);
    audit.param2[0] = '\0';
    logs.push_back(audit);
}
bool EventRegistry::turnErrosIntoWarnings() {
bool EventRegistry::turnErrorsIntoWarnings() {
    bool eventFound = false;
    for (auto it = logs.begin(); it != logs.end(); ++it) {
        if (it->severity == SVRT_ERROR) {
@@ -112,9 +157,14 @@
    return eventFound;
}
void EventRegistry::exportLastEvents(AuditEvent* auditEvents, int nlogs) {
void EventRegistry::exportLastEvents(AuditEvent *auditEvents, int nlogs) {
    const int sizeToCopy = min(nlogs, (int) logs.size());
    std::copy(logs.begin(), logs.begin() + sizeToCopy, auditEvents);
    std::copy(logs.end() - sizeToCopy, logs.end(), auditEvents);
}
bool EventRegistry::isGood() const {
    return getLastFailure() == nullptr;
}
}
src/library/base/EventRegistry.h
@@ -2,7 +2,7 @@
 * EventRegistry.h
 *
 *  Created on: Mar 30, 2014
 *
 *
 */
#ifndef EVENTREGISTRY_H_
@@ -10,43 +10,51 @@
#include "../api/datatypes.h"
#include <vector>
#include <map>
#include <set>
#include <string>
namespace license {
/*
 AuditEvent error_event_builder(EVENT_TYPE event);
 AuditEvent audit_event_builder(EVENT_TYPE event, SEVERITY severity);
 AuditEvent audit_event_builder(EVENT_TYPE event, SEVERITY severity,
 const string& eventParameter);*/
/**
 * Tracks the events relative to a license and provide explanation regarding
 * failures to verify licenses.
 */
class EventRegistry {
private:
    friend EventRegistry& operator<<(EventRegistry&, AuditEvent&);
    friend EventRegistry& operator<<(EventRegistry&, EventRegistry&);
    //TODO change into map
    friend std::ostream & operator << (std::ostream &out, const EventRegistry &er);
    std::vector<AuditEvent> logs;
    //Forbid copy
    //EventRegistry(const EventRegistry& that) = delete;
    /**
     * For every license keep track of the events who progressed most
     * in the validation process
     */
    std::map<std::string,int> mostAdvancedLogIdx_by_LicenseId;
    int current_validation_step;
public:
    EventRegistry();
    //operator <<
    void append(const EventRegistry &eventRegistry);
    void turnLastEventIntoError();
    bool turnEventIntoError(EVENT_TYPE event);
    bool turnErrosIntoWarnings();
    /**
     * Turn the event warning for the license with the most advanced status
     * into an error.
     */
    bool turnWarningsIntoErrors();
    bool turnErrorsIntoWarnings();
    bool isGood() const;
    /**
     * Return the last failure (event with warn or error status)
     * for the license with the most advanced status.
     * @return NULL if no failures are found.
     */
    AuditEvent const* getLastFailure() const;
    bool isGood() const;
    void addError(EVENT_TYPE event);
    void addEvent(EVENT_TYPE event, SEVERITY severity);
    void addEvent(EVENT_TYPE event, SEVERITY severity,
            const std::string &eventParameter);
    void addEvent(EVENT_TYPE event, const std::string &licenseLocationId);
    void addEvent(EVENT_TYPE event, const char *licenseLocationId = nullptr,
            const char *info = nullptr);
    void exportLastEvents(AuditEvent *auditEvents, int nlogs);
};
}
#endif /* EVENTREGISTRY_H_ */
src/library/base/FileUtils.cpp
@@ -9,19 +9,24 @@
#include <string>
#include <cerrno>
#include <iostream>
#include <algorithm>
#include <algorithm>
#include "FileUtils.hpp"
namespace license {
using namespace std;
vector<string> filter_existing_files(const vector<string> &fileList) {
vector<string> filter_existing_files(const vector<string> &fileList,
        EventRegistry& registry,const char* extraData) {
    vector<string> existingFiles;
    for (auto it = fileList.begin(); it != fileList.end(); it++) {
        registry.addEvent(LICENSE_SPECIFIED,it->c_str(), extraData);
        ifstream f(it->c_str());
        if (f.good()) {
            existingFiles.push_back(*it);
            registry.addEvent(LICENSE_FOUND,it->c_str(),extraData);
        } else {
            registry.addEvent(LICENSE_FILE_NOT_FOUND,it->c_str(), extraData);
        }
        f.close();
    }
@@ -57,7 +62,7 @@
        return (dotpos == 0 ? path : path.substr(0, dotpos));
    } else if(pathsep_pos >= dotpos +1) {
        return path;
    }
    }
    return path.substr(0, dotpos);
}
src/library/base/FileUtils.hpp
@@ -2,17 +2,18 @@
 * FileUtils.h
 *
 *  Created on: Apr 8, 2019
 *
 *
 */
#ifndef FILEUTILS_H_
#define FILEUTILS_H_
#include <string>
#include <vector>
#include "EventRegistry.h"
namespace license {
std::vector<std::string> filter_existing_files(const std::vector<std::string>& fileList);
std::vector<std::string> filter_existing_files(const std::vector<std::string>& fileList,EventRegistry& registry, const char* extraData);
std::string get_file_contents(const char *filename,size_t max_size);
std::string remove_extension(const std::string& path);
src/library/base/StringUtils.cpp
@@ -2,17 +2,18 @@
 * StringUtils.cpp
 *
 *  Created on: Apr 8, 2014
 *
 *
 */
#include <cctype> //toupper
#include "StringUtils.h"
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <stdexcept>
#include <regex>
#include "StringUtils.h"
#ifdef _WIN32
#include <time.h> //mktime under windows
@@ -21,7 +22,7 @@
namespace license {
using namespace std;
string trim_copy(const string& string_to_trim) {
string trim_copy(const string &string_to_trim) {
    std::string::const_iterator it = string_to_trim.begin();
    while (it != string_to_trim.end() && isspace(*it))
        it++;
@@ -33,13 +34,13 @@
    return std::string(it, rit.base());
}
string toupper_copy(const string& lowercase) {
string toupper_copy(const string &lowercase) {
    string cp(lowercase);
    std::transform(cp.begin(), cp.end(), cp.begin(), (int (*)(int))toupper);
    std::transform(cp.begin(), cp.end(), cp.begin(), (int (*)(int)) toupper);
    return cp;
}
time_t seconds_from_epoch(const char* timeString) {
time_t seconds_from_epoch(const char *timeString) {
    int year, month, day;
    tm tm;
    if (strlen(timeString) == 8) {
@@ -48,14 +49,16 @@
            throw invalid_argument("Date not recognized");
        }
    } else if (strlen(timeString) == 10) {
        const int nfield = sscanf(timeString, "%4d-%2d-%2d", &year, &month, &day);
        const int nfield = sscanf(timeString, "%4d-%2d-%2d", &year, &month,
                &day);
        if (nfield != 3) {
            const int nfield = sscanf(timeString, "%4d/%2d/%2d", &year, &month, &day);
            const int nfield = sscanf(timeString, "%4d/%2d/%2d", &year, &month,
                    &day);
            if (nfield != 3) {
                throw invalid_argument("Date not recognized");
            }
        }
    } else{
    } else {
        throw invalid_argument("Date not recognized");
    }
    tm.tm_isdst = -1;
@@ -70,8 +73,8 @@
    return mktime(&tm);
}
const vector<string> split_string(const string& licensePositions,char splitchar) {
const vector<string> split_string(const string &licensePositions,
        char splitchar) {
    std::stringstream streamToSplit(licensePositions);
    std::string segment;
    std::vector<string> seglist;
@@ -82,4 +85,18 @@
    return seglist;
}
const static regex iniSection("\\[.*?\\]");
const static regex b64(
        "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$");
FILE_FORMAT identify_format(const string &license) {
    FILE_FORMAT result = UNKNOWN;
    if (regex_match(license, b64)) {
        result = BASE64;
    } else if (regex_search(license, iniSection)) {
        result = INI;
    }
    return result;
}
} /* namespace license */
src/library/base/StringUtils.h
@@ -2,11 +2,13 @@
 * StringUtils.h
 *
 *  Created on: Apr 8, 2014
 *
 *
 */
#ifndef STRINGUTILS_H_
#define STRINGUTILS_H_
#include <bits/types/time_t.h>
#include <string>
#include <vector>
@@ -28,7 +30,14 @@
/**
 * Split a string on a given character
 */
const vector<string> split_string(const string& licensePositions, const char splitchar);
const vector<string> split_string(const string& stringToBeSplit, const char splitchar);
typedef enum {
    INI, BASE64, UNKNOWN
} FILE_FORMAT;
FILE_FORMAT identify_format(const string& license);
}
/* namespace license */
src/library/base/base64.c
New file
@@ -0,0 +1,133 @@
#include <stdio.h>
#include <stdlib.h>
const static char* b64 =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// maps A=>0,B=>1..
const static unsigned char unb64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
        0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
        54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
        0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
        25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
        49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
        0, 0, 0, 0, 0, 0, }; // This array has 255 elements
//review api
char* base64(const void* binaryData, int len, int *flen) {
    const unsigned char* bin = (const unsigned char*) binaryData;
    char* res;
    int rc = 0; // result counter
    int byteNo; // I need this after the loop
    int modulusLen = len % 3;
    int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0.
    *flen = 4 * (len + pad) / 3;
    res = (char*) malloc(*flen + 1); // and one for the null
    if (!res) {
        puts("ERROR: base64 could not allocate enough memory.");
        puts("I must stop because I could not get enough");
        return 0;
    }
    for (byteNo = 0; byteNo <= len - 3; byteNo += 3) {
        unsigned char BYTE0 = bin[byteNo];
        unsigned char BYTE1 = bin[byteNo + 1];
        unsigned char BYTE2 = bin[byteNo + 2];
        res[rc++] = b64[BYTE0 >> 2];
        res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)];
        res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)];
        res[rc++] = b64[0x3f & BYTE2];
    }
    if (pad == 2) {
        res[rc++] = b64[bin[byteNo] >> 2];
        res[rc++] = b64[(0x3 & bin[byteNo]) << 4];
        res[rc++] = '=';
        res[rc++] = '=';
    } else if (pad == 1) {
        res[rc++] = b64[bin[byteNo] >> 2];
        res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)];
        res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2];
        res[rc++] = '=';
    }
    res[rc] = 0; // NULL TERMINATOR! ;)
    return res;
}
unsigned char* unbase64(const char* ascii, int len, int *flen) {
    const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
    unsigned char *bin;
    int cb = 0;
    int charNo;
    int pad = 0;
    if (len < 2) { // 2 accesses below would be OOB.
        // catch empty string, return NULL as result.
        puts(
                "ERROR: You passed an invalid base64 string (too short). You get NULL back.");
        *flen = 0;
        return 0;
    }
    if (safeAsciiPtr[len - 1] == '=')
        ++pad;
    if (safeAsciiPtr[len - 2] == '=')
        ++pad;
    *flen = 3 * len / 4 - pad;
    bin = (unsigned char*) malloc(*flen);
    if (!bin) {
        puts("ERROR: unbase64 could not allocate enough memory.");
        puts("I must stop because I could not get enough");
        return 0;
    }
    for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        int C = unb64[safeAsciiPtr[charNo + 2]];
        int D = unb64[safeAsciiPtr[charNo + 3]];
        bin[cb++] = (A << 2) | (B >> 4);
        bin[cb++] = (B << 4) | (C >> 2);
        bin[cb++] = (C << 6) | (D);
    }
    if (pad == 1) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        int C = unb64[safeAsciiPtr[charNo + 2]];
        bin[cb++] = (A << 2) | (B >> 4);
        bin[cb++] = (B << 4) | (C >> 2);
    } else if (pad == 2) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        bin[cb++] = (A << 2) | (B >> 4);
    }
    return bin;
}
src/library/base/base64.h
@@ -31,140 +31,14 @@
#ifndef BASE64_H
#define BASE64_H
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
const static char* b64 =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char* unbase64(const char* ascii, int len, int *flen);
char* base64(const void* binaryData, int len, int *flen);
// maps A=>0,B=>1..
const static unsigned char unb64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
        0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
        54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
        0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
        25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
        49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
        0, 0, 0, 0, 0, 0, }; // This array has 255 elements
// Converts binary data of length=len to base64 characters.
// Length of the resultant string is stored in flen
// (you must pass pointer flen).
char* base64(const void* binaryData, int len, int *flen) {
    const unsigned char* bin = (const unsigned char*) binaryData;
    char* res;
    int rc = 0; // result counter
    int byteNo; // I need this after the loop
    int modulusLen = len % 3;
    int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0.
    *flen = 4 * (len + pad) / 3;
    res = (char*) malloc(*flen + 1); // and one for the null
    if (!res) {
        puts("ERROR: base64 could not allocate enough memory.");
        puts("I must stop because I could not get enough");
        return 0;
    }
    for (byteNo = 0; byteNo <= len - 3; byteNo += 3) {
        unsigned char BYTE0 = bin[byteNo];
        unsigned char BYTE1 = bin[byteNo + 1];
        unsigned char BYTE2 = bin[byteNo + 2];
        res[rc++] = b64[BYTE0 >> 2];
        res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)];
        res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)];
        res[rc++] = b64[0x3f & BYTE2];
    }
    if (pad == 2) {
        res[rc++] = b64[bin[byteNo] >> 2];
        res[rc++] = b64[(0x3 & bin[byteNo]) << 4];
        res[rc++] = '=';
        res[rc++] = '=';
    } else if (pad == 1) {
        res[rc++] = b64[bin[byteNo] >> 2];
        res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)];
        res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2];
        res[rc++] = '=';
    }
    res[rc] = 0; // NULL TERMINATOR! ;)
    return res;
#ifdef __cplusplus
}
unsigned char* unbase64(const char* ascii, int len, int *flen) {
    const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
    unsigned char *bin;
    int cb = 0;
    int charNo;
    int pad = 0;
    if (len < 2) { // 2 accesses below would be OOB.
        // catch empty string, return NULL as result.
        puts(
                "ERROR: You passed an invalid base64 string (too short). You get NULL back.");
        *flen = 0;
        return 0;
    }
    if (safeAsciiPtr[len - 1] == '=')
        ++pad;
    if (safeAsciiPtr[len - 2] == '=')
        ++pad;
    *flen = 3 * len / 4 - pad;
    bin = (unsigned char*) malloc(*flen);
    if (!bin) {
        puts("ERROR: unbase64 could not allocate enough memory.");
        puts("I must stop because I could not get enough");
        return 0;
    }
    for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        int C = unb64[safeAsciiPtr[charNo + 2]];
        int D = unb64[safeAsciiPtr[charNo + 3]];
        bin[cb++] = (A << 2) | (B >> 4);
        bin[cb++] = (B << 4) | (C >> 2);
        bin[cb++] = (C << 6) | (D);
    }
    if (pad == 1) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        int C = unb64[safeAsciiPtr[charNo + 2]];
        bin[cb++] = (A << 2) | (B >> 4);
        bin[cb++] = (B << 4) | (C >> 2);
    } else if (pad == 2) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        bin[cb++] = (A << 2) | (B >> 4);
    }
    return bin;
}
#endif
#endif
src/library/license++.cpp
@@ -1,6 +1,6 @@
//============================================================================
// Name        : license-manager-cpp.cpp
// Author      :
// Author      :
// Version     :
// Copyright   : BSD
//============================================================================
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include "api/license++.h"
@@ -41,7 +42,7 @@
}
EVENT_TYPE acquire_license(const char * product,
        LicenseLocation licenseLocation, LicenseInfo* license) {
        const LicenseLocation* licenseLocation, LicenseInfo* licenseInfoOut) {
    license::LicenseReader lr = license::LicenseReader(licenseLocation);
    vector<license::FullLicenseInfo> licenses;
    license::EventRegistry er = lr.readLicenses(string(product), licenses);
@@ -50,28 +51,32 @@
        vector<license::FullLicenseInfo> licenses_with_errors;
        vector<license::FullLicenseInfo> licenses_ok;
        for (auto it = licenses.begin(); it != licenses.end(); it++) {
            license::EventRegistry validation_er = it->validate(0);
            if (validation_er.isGood()) {
            bool valid = it->validate(0,er);
            if (valid) {
                licenses_ok.push_back(*it);
            } else {
                licenses_with_errors.push_back(*it);
            }
            er.append(validation_er);
        }
        if (licenses_ok.size() > 0) {
            er.turnErrosIntoWarnings();
            er.turnErrorsIntoWarnings();
            result = LICENSE_OK;
            mergeLicenses(licenses_ok, license);
            mergeLicenses(licenses_ok, licenseInfoOut);
        } else {
            er.turnWarningsIntoErrors();
            result = er.getLastFailure()->event_type;
            mergeLicenses(licenses_with_errors, license);
            mergeLicenses(licenses_with_errors, licenseInfoOut);
        }
    } else {
        er.turnWarningsIntoErrors();
        result = er.getLastFailure()->event_type;
    }
    if (license != nullptr) {
        er.exportLastEvents(license->status, 5);
#ifdef _DEBUG
    cout << er <<endl;
#endif
    if (licenseInfoOut != nullptr) {
        er.exportLastEvents(licenseInfoOut->status, AUDIT_EVENT_NUM);
    }
    return result;
}
src/library/locate/ApplicationFolder.cpp
@@ -23,18 +23,15 @@
namespace locate {
using namespace std;
ApplicationFolder::ApplicationFolder() :
        LocatorStrategy("ApplicationFolder") {
}
ApplicationFolder::~ApplicationFolder() {
}
const vector<string> ApplicationFolder::licenseLocations(
        EventRegistry &eventRegistry) const {
const vector<string> ApplicationFolder::license_locations(
        EventRegistry &eventRegistry) {
    vector<string> diskFiles;
    char fname[MAX_PATH] = { 0 };
    const FUNCTION_RETURN fret = getModuleName(fname);
@@ -44,11 +41,9 @@
        ifstream f(temptativeLicense.c_str());
        if (f.good()) {
            diskFiles.push_back(temptativeLicense);
            eventRegistry.addEvent((EVENT_TYPE) LICENSE_FILE_FOUND,
                    (SEVERITY) SVRT_INFO, temptativeLicense);
            eventRegistry.addEvent(LICENSE_FOUND, temptativeLicense.c_str());
        } else {
            eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN,
                    temptativeLicense);
            eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, temptativeLicense.c_str());
        }
        f.close();
    } else {
src/library/locate/ApplicationFolder.hpp
@@ -18,7 +18,7 @@
class ApplicationFolder: public LocatorStrategy {
public:
    ApplicationFolder();
    virtual const std::vector<std::string> licenseLocations(EventRegistry& eventRegistry) const;
    virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry);
    virtual ~ApplicationFolder();
};
src/library/locate/EnvironmentVarData.cpp
@@ -6,6 +6,18 @@
 */
#include "EnvironmentVarData.hpp"
#include <build_properties.h>
#include <cstdlib>
#include <regex>
#include <string>
#include <vector>
#include "../api/datatypes.h"
#include "../base/base64.h"
#include "../base/EventRegistry.h"
#include "../base/StringUtils.h"
namespace license {
namespace locate {
@@ -18,15 +30,37 @@
EnvironmentVarData::~EnvironmentVarData() {
}
const vector<string> EnvironmentVarData::licenseLocations(
        EventRegistry &eventRegistry) const {
const vector<string> EnvironmentVarData::license_locations(
        EventRegistry &eventRegistry) {
    vector<string> diskFiles;
    char *env_var_value = getenv(LICENSE_DATA_ENV_VAR);
    if (env_var_value != nullptr && env_var_value[0] != '\0') {
        eventRegistry.addEvent(LICENSE_SPECIFIED, LICENSE_LOCATION_ENV_VAR);
        FILE_FORMAT licenseFormat = identify_format(env_var_value);
        if (licenseFormat == UNKNOWN) {
            eventRegistry.addEvent(LICENSE_MALFORMED, LICENSE_LOCATION_ENV_VAR);
        } else {
            diskFiles.push_back(LICENSE_LOCATION_ENV_VAR);
            isBase64 = (licenseFormat == BASE64);
        }
    } else {
        eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED,
        LICENSE_LOCATION_ENV_VAR);
    }
    return diskFiles;
}
const std::string EnvironmentVarData::retrieveLicense(const std::string &licenseLocation) const{
    return "";
const std::string EnvironmentVarData::retrieve_license_content(
        const std::string &licenseLocation) const {
    string tmpVal = getenv(LICENSE_LOCATION_ENV_VAR);
    if (isBase64) {
        int flen = 0;
        unsigned char *raw = unbase64(tmpVal.c_str(), tmpVal.length(), &flen);
        string str = string(reinterpret_cast<char*>(raw));
        free(raw);
        return str;
    }
    return tmpVal;
}
}
src/library/locate/EnvironmentVarData.hpp
@@ -14,11 +14,12 @@
namespace locate {
class EnvironmentVarData: public LocatorStrategy {
private:
    bool isBase64 = false;
public:
    EnvironmentVarData();
    virtual const std::vector<std::string> licenseLocations(EventRegistry& eventRegistr) const;
    virtual const std::string retrieveLicense(const std::string &licenseLocation) const;
    virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistr);
    virtual const std::string retrieve_license_content(const std::string &licenseLocation) const;
    virtual ~EnvironmentVarData();
};
src/library/locate/EnvironmentVarLocation.cpp
@@ -22,8 +22,8 @@
EnvironmentVarLocation::~EnvironmentVarLocation() {
}
const vector<string> EnvironmentVarLocation::licenseLocations(
        EventRegistry &eventRegistry) const {
const vector<string> EnvironmentVarLocation::license_locations(
        EventRegistry &eventRegistry) {
    vector<string> licenseFileFoundWithEnvVariable;
    const string varName(LICENSE_LOCATION_ENV_VAR);
@@ -33,20 +33,10 @@
        if (env_var_value != nullptr && env_var_value[0] != '\0') {
            const vector<string> declared_positions = license::split_string(
                    string(env_var_value), ';');
            vector<string> existing_pos = license::filter_existing_files(
                    declared_positions);
            if (existing_pos.size() > 0) {
                for (auto it = existing_pos.begin(); it != existing_pos.end();
                        ++it) {
                    licenseFileFoundWithEnvVariable.push_back(*it);
                    eventRegistry.addEvent(LICENSE_FILE_FOUND, SVRT_INFO, *it);
                }
            } else {
                eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN,
                        env_var_value);
            }
            licenseFileFoundWithEnvVariable = license::filter_existing_files(
                    declared_positions, eventRegistry, LICENSE_LOCATION_ENV_VAR);
        } else {
            eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, SVRT_WARN);
            eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED);
        }
    }
    return licenseFileFoundWithEnvVariable;
src/library/locate/EnvironmentVarLocation.hpp
@@ -17,7 +17,7 @@
public:
    EnvironmentVarLocation();
    virtual const std::vector<std::string> licenseLocations(EventRegistry& eventRegistry) const;
    virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry);
    virtual ~EnvironmentVarLocation();
};
src/library/locate/ExternalDefinition.cpp
@@ -5,36 +5,72 @@
 *      Author: Gabriele Contini
 */
#include "../base/StringUtils.h"
#include <stdlib.h>
#include <cstring>
#include <string>
#include <vector>
#include "../api/datatypes.h"
#include "../base/base64.h"
#include "../base/EventRegistry.h"
#include "../base/FileUtils.hpp"
#include "../base/StringUtils.h"
#include "ExternalDefinition.hpp"
namespace license {
namespace locate {
using namespace std;
ExternalDefinition::ExternalDefinition(const char *location) :
ExternalDefinition::ExternalDefinition(const LicenseLocation *location) :
        LocatorStrategy("ExternalDefinition"), m_location(location) {
}
ExternalDefinition::~ExternalDefinition() {
}
const std::vector<std::string> ExternalDefinition::licenseLocations(
        EventRegistry &eventRegistry) const {
    const vector<string> declared_positions = license::split_string(m_location,
            ';');
    const vector<string> existing_pos = license::filter_existing_files(
            declared_positions);
    if (existing_pos.size() > 0) {
        for (auto it = existing_pos.begin(); it != existing_pos.end(); ++it) {
            eventRegistry.addEvent(LICENSE_FILE_FOUND, SVRT_INFO, *it);
const std::vector<std::string> ExternalDefinition::license_locations(
        EventRegistry &eventRegistry) {
    vector<string> existing_pos;
    if (m_location->licenseData != nullptr
            && m_location->licenseData[0] != '\0') {
        eventRegistry.addEvent(LICENSE_SPECIFIED, get_strategy_name());
        FILE_FORMAT licenseFormat = identify_format(m_location->licenseData);
        if (licenseFormat == UNKNOWN) {
            eventRegistry.addEvent(LICENSE_MALFORMED, get_strategy_name());
        } else {
            existing_pos.push_back(get_strategy_name());
            licenseDataIsBase64 = (licenseFormat == BASE64);
        }
    } else {
        eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN, m_location);
    }
    if (m_location->licenseFileLocation != nullptr
            && strlen(m_location->licenseFileLocation) > 0) {
        const vector<string> declared_positions = license::split_string(
                m_location->licenseFileLocation, ';');
        existing_pos = license::filter_existing_files(declared_positions,
                eventRegistry, get_strategy_name().c_str());
    }
    return existing_pos;
}
const std::string ExternalDefinition::retrieve_license_content(
        const std::string &licenseLocation) const {
    if (licenseLocation == get_strategy_name()) {
        if (licenseDataIsBase64) {
            int flen = 0;
            unsigned char *raw = unbase64(m_location->licenseData,
                    strlen(m_location->licenseData), &flen);
            string str = string(reinterpret_cast<char*>(raw));
            free(raw);
            return str;
        } else {
            return m_location->licenseData;
        }
    } else {
        return LocatorStrategy::retrieve_license_content(licenseLocation);
    }
}
} /* namespace locate */
} /* namespace license */
src/library/locate/ExternalDefinition.hpp
@@ -15,10 +15,12 @@
class ExternalDefinition: public LocatorStrategy {
private:
    const std::string m_location;
    const LicenseLocation* m_location;
    bool licenseDataIsBase64 = false;
public:
    ExternalDefinition(const char* location);
    virtual const std::vector<std::string> licenseLocations(EventRegistry& eventRegistry) const;
    ExternalDefinition(const LicenseLocation* location);
    virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry);
    virtual const std::string retrieve_license_content(const std::string &licenseLocation) const;
    virtual ~ExternalDefinition();
};
src/library/locate/LocatorFactory.cpp
@@ -10,34 +10,32 @@
#include "LocatorStrategy.hpp"
#include "LocatorFactory.hpp"
#include "ApplicationFolder.hpp"
//#include "EnvironmentVarData.hpp"
#include "EnvironmentVarData.hpp"
#include "EnvironmentVarLocation.hpp"
#include "ExternalDefinition.hpp"
namespace license {
namespace locate {
using namespace std;
FUNCTION_RETURN LocatorFactory::getActiveStrategies(
        vector<unique_ptr<LocatorStrategy>> &strategies,
        const char *locationHint) {
FUNCTION_RETURN LocatorFactory::get_active_strategies(
        std::vector<std::unique_ptr<LocatorStrategy>> &strategies,
        const LicenseLocation *locationHint) {
#if(FIND_LICENSE_NEAR_MODULE)
    strategies.push_back(
            unique_ptr<LocatorStrategy>(
            std::unique_ptr<LocatorStrategy>(
                    (LocatorStrategy*) new ApplicationFolder()));
#endif
#if(FIND_LICENSE_WITH_ENV_VAR)
    strategies.push_back(
            unique_ptr<LocatorStrategy>(
            std::unique_ptr<LocatorStrategy>(
                    (LocatorStrategy*) new EnvironmentVarLocation()));
//    strategies.push_back(
//            unique_ptr<LocatorStrategy>(
//                    (LocatorStrategy*) new EnvironmentVarData()));
    strategies.push_back(
            std::unique_ptr<LocatorStrategy>(
                    (LocatorStrategy*) new EnvironmentVarData()));
#endif
    if (locationHint != nullptr) {
        strategies.push_back(
                unique_ptr<LocatorStrategy>(
                std::unique_ptr<LocatorStrategy>(
                        (LocatorStrategy*) new ExternalDefinition(locationHint)));
    }
    return strategies.size() > 0 ? FUNC_RET_OK : FUNC_RET_NOT_AVAIL;
src/library/locate/LocatorFactory.hpp
@@ -6,6 +6,7 @@
#include <vector>
#include "../base/base.h"
#include "../api/datatypes.h"
#include "LocatorStrategy.hpp"
namespace license {
@@ -19,9 +20,9 @@
    }
public:
    static FUNCTION_RETURN getActiveStrategies(
    static FUNCTION_RETURN get_active_strategies(
            std::vector<std::unique_ptr<LocatorStrategy>> &strategiesOut,
            const char *locationHint);
            const LicenseLocation *locationHint);
};
src/library/locate/LocatorStrategy.cpp
@@ -14,7 +14,7 @@
namespace locate {
using namespace std;
const string LocatorStrategy::retrieveLicense(
const string LocatorStrategy::retrieve_license_content(
        const string &licenseLocation) const {
    return get_file_contents(licenseLocation.c_str(), MAX_LICENSE_LENGTH);
}
src/library/locate/LocatorStrategy.hpp
@@ -31,18 +31,26 @@
    virtual const std::string get_strategy_name() const {
        return m_strategy_name;
    }
    virtual const std::vector<std::string> licenseLocations(
            EventRegistry &eventRegistry) const = 0;
    /**
     * Try to find licenses
     * @param eventRegistry
     * @return
     * A list of identifiers for call retrieve_license_content.
     */
    virtual const std::vector<std::string> license_locations(
            EventRegistry &eventRegistry) = 0;
    /**
     * Default implementation is to retrieve the license from file.
     * Subclasses may override it.
     * @param licenseLocation
     * @param licenseLocationId
     *     String that identifies the license. It is usually the file name
     *     but can be whatever is understood by the class
     * @return
     *     a string containing the license data in INI format.
     */
    virtual const std::string retrieveLicense(
            const std::string &licenseLocation) const;
    virtual const std::string retrieve_license_content(
            const std::string &licenseLocationId) const;
    inline virtual ~LocatorStrategy() {
    }
};
src/library/os/os.h
@@ -2,7 +2,7 @@
 * os-dependent.hpp
 *
 *  Created on: Mar 29, 2014
 *
 *
 */
#ifndef OS_DEPENDENT_HPP_
@@ -79,6 +79,14 @@
FUNCTION_RETURN verifySignature(const char* stringToVerify, const char* signatureB64);
#ifdef _WIN32
#define SETENV(VAR,VAL) _putenv_s(VAR, VAL);
#define    UNSETENV(P) _putenv_s(P, "");
#else
#define SETENV(VAR,VAL) setenv(VAR, VAL, 1);
#define    UNSETENV(P)    unsetenv(P);
#endif
#ifdef __cplusplus
}
#endif
src/tools/base_lib/win/CryptoHelperWindows.cpp
@@ -1,394 +1,394 @@
/*
 * CryptoHelperWindows.cpp
 *
 *  Created on: Sep 14, 2014
 *
 */
#include <sstream>
#include <vector>
#include <string>
#include "CryptoHelperWindows.h"
// The RSA public-key key exchange algorithm
#define ENCRYPT_ALGORITHM         CALG_RSA_SIGN
// The high order WORD 0x0200 (decimal 512)
// determines the key length in bits.
#define KEYLENGTH                 0x02000000
#pragma comment(lib, "crypt32.lib")
namespace license {
CryptoHelperWindows::CryptoHelperWindows() {
    m_hCryptProv = NULL;
    m_hCryptKey = NULL;
    if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, 0)) {
        // If the key container cannot be opened, try creating a new
        // container by specifying a container name and setting the
        // CRYPT_NEWKEYSET flag.
        DWORD lastError = GetLastError();
        printf("Error in CryptAcquireContext (1) 0x%08x \n", lastError);
        if (NTE_BAD_KEYSET == lastError) {
            if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
                printf("Warn in CryptAcquireContext: acquiring new user keyset failed 0x%08x, trying less secure mackine keyset \n", GetLastError());
                //maybe access to protected storage disabled. Try with machine keys (less secure)
                if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) {
                    printf("Error in CryptAcquireContext (2) 0x%08x \n", GetLastError());
                    if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)) {
                        printf("Error in CryptAcquireContext (3): acquiring new keyset(machine) failed 0x%08x \n", GetLastError());
                        throw logic_error("");
                    }
                }
            }
        } else {
            printf(" Error in CryptAcquireContext (4) 0x%08x \n", lastError);
            throw logic_error("");
        }
    }
}
/**
 This method calls the CryptGenKey function to get a handle to an
 exportable key-pair. The key-pair is  generated with the RSA public-key
 key exchange algorithm using Microsoft Enhanced Cryptographic Provider.
 */
void CryptoHelperWindows::generateKeyPair() {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    // If the handle to key container is NULL, fail.
    if (m_hCryptProv == NULL)
        throw logic_error("Cryptocontext not correctly initialized");
    // Release a previously acquired handle to key-pair.
    if (m_hCryptKey)
        m_hCryptKey = NULL;
    // Call the CryptGenKey method to get a handle
    // to a new exportable key-pair.
    if (!CryptGenKey(m_hCryptProv, ENCRYPT_ALGORITHM,
    KEYLENGTH | CRYPT_EXPORTABLE, &m_hCryptKey)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error generating keys ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    //double check the key is really generated
    if(m_hCryptKey == NULL) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error generating keys (2)")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
}
/* This method calls the CryptExportKey function to get the Public key
 in a string suitable for C source inclusion.
 */
const string CryptoHelperWindows::exportPublicKey() const {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    DWORD dwBlobLen;
    BYTE *pbKeyBlob = nullptr;
    stringstream ss;
    // If the handle to key container is NULL, fail.
    if (m_hCryptKey == NULL)
        throw logic_error("call GenerateKey first.");
    // This call here determines the length of the key
    // blob.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PUBLICKEYBLOB, 0, nullptr, &dwBlobLen)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error calculating size of public key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    // Allocate memory for the pbKeyBlob.
    if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) {
        throw logic_error(string("Out of memory exporting public key "));
    }
    // Do the actual exporting into the key BLOB.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        delete pbKeyBlob;
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error exporting public key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    } else {
        ss << "\t";
        for (unsigned int i = 0; i < dwBlobLen; i++) {
            if (i != 0) {
                ss << ", ";
                if (i % 10 == 0) {
                    ss << "\\" << endl << "\t";
                }
            }
            ss << to_string(static_cast<long long>(pbKeyBlob[i]));
        }
        delete pbKeyBlob;
    }
    return ss.str();
}
CryptoHelperWindows::~CryptoHelperWindows() {
    if (m_hCryptProv) {
        CryptReleaseContext(m_hCryptProv, 0);
        m_hCryptProv = NULL;
    }
    if (m_hCryptKey)
        m_hCryptKey = NULL;
}
//--------------------------------------------------------------------
// This method calls the CryptExportKey function to get the Private key
// in a byte array. The byte array is allocated on the heap and the size
// of this is returned to the caller. The caller is responsible for releasing // this memory using a delete call.
//--------------------------------------------------------------------
const string CryptoHelperWindows::exportPrivateKey() const {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    DWORD dwBlobLen;
    BYTE *pbKeyBlob;
    stringstream ss;
    // If the handle to key container is NULL, fail.
    if (m_hCryptKey == NULL)
        throw logic_error(string("call GenerateKey first."));
    // This call here determines the length of the key
    // blob.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PRIVATEKEYBLOB, 0, nullptr, &dwBlobLen)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error calculating size of private key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    // Allocate memory for the pbKeyBlob.
    if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) {
        throw logic_error(string("Out of memory exporting private key "));
    }
    // Do the actual exporting into the key BLOB.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PRIVATEKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        delete pbKeyBlob;
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error exporting private key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    } else {
        ss << "\t";
        for (unsigned int i = 0; i < dwBlobLen; i++) {
            if (i != 0) {
                ss << ", ";
                if (i % 15 == 0) {
                    ss << "\\" << endl << "\t";
                }
            }
            ss << to_string(static_cast<long long>(pbKeyBlob[i]));
        }
        delete pbKeyBlob;
    }
    return ss.str();
}
void CryptoHelperWindows::printHash(HCRYPTHASH *hHash) const {
    BYTE *pbHash;
    DWORD dwHashLen;
    DWORD dwHashLenSize = sizeof(DWORD);
    char *hashStr;
    unsigned int i;
    if (CryptGetHashParam(*hHash, HP_HASHSIZE, (BYTE*) &dwHashLen,
            &dwHashLenSize, 0)) {
        pbHash = (BYTE*) malloc(dwHashLen);
        hashStr = (char*) malloc(dwHashLen * 2 + 1);
        if (CryptGetHashParam(*hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) {
            for (i = 0; i < dwHashLen; i++) {
                sprintf(&hashStr[i * 2], "%02x", pbHash[i]);
            }
            printf("hash To be signed: %s \n", hashStr);
        }
        free(pbHash);
        free(hashStr);
    }
}
const string CryptoHelperWindows::signString(const void *privateKey,
        size_t pklen, const string &license) const {
    BYTE *pbBuffer = (BYTE*) license.c_str();
    const DWORD dwBufferLen = (DWORD) strlen((char*) pbBuffer);
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD strLen;
    //-------------------------------------------------------------------
    // Acquire a cryptographic provider context handle.
    if (!CryptImportKey(m_hCryptProv, (const BYTE*) privateKey, (DWORD) pklen,
            0, 0, &hKey)) {
        throw logic_error(
                string("Error in importing the PrivateKey ")
                        + to_string(static_cast<long long>(GetLastError())));
    }
    //-------------------------------------------------------------------
    // Create the hash object.
    if (CryptCreateHash(m_hCryptProv, CALG_SHA1, 0, 0, &hHash)) {
        printf("Hash object created. \n");
    } else {
        CryptDestroyKey(hKey);
        throw logic_error(string("Error during CryptCreateHash."));
    }
    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    if (CryptHashData(hHash, pbBuffer, dwBufferLen, 0)) {
#ifdef _DEBUG
        printf("Length of data to be hashed: %d \n", dwBufferLen);
        printHash(&hHash);
#endif
    } else {
        throw logic_error(string("Error during CryptHashData."));
    }
    //-------------------------------------------------------------------
    // Determine the size of the signature and allocate memory.
    dwSigLen = 0;
    if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, nullptr, &dwSigLen)) {
        printf("Signature length %d found.\n", dwSigLen);
    } else {
        throw logic_error(string("Error during CryptSignHash."));
    }
    //-------------------------------------------------------------------
    // Allocate memory for the signature buffer.
    if (pbSignature = (BYTE*) malloc(dwSigLen)) {
        printf("Memory allocated for the signature.\n");
    } else {
        throw logic_error(string("Out of memory."));
    }
    //-------------------------------------------------------------------
    // Sign the hash object.
    if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, pbSignature,
            &dwSigLen)) {
        printf("pbSignature is the signature length. %d\n", dwSigLen);
    } else {
        throw logic_error(string("Error during CryptSignHash."));
    }
    //-------------------------------------------------------------------
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    CryptDestroyKey(hKey);
    CryptBinaryToString(pbSignature, dwSigLen,
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &strLen);
    vector<char> buffer(strLen);
    CryptBinaryToString(pbSignature, dwSigLen,
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, &buffer[0], &strLen);
    //-------------------------------------------------------------------
    // In the second phase, the hash signature is verified.
    // This would most often be done by a different user in a
    // separate program. The hash, signature, and the PUBLICKEYBLOB
    // would be read from a file, an email message,
    // or some other source.
    // Here, the original pbBuffer, pbSignature, szDescription.
    // pbKeyBlob, and their lengths are used.
    // The contents of the pbBuffer must be the same data
    // that was originally signed.
    //-------------------------------------------------------------------
    // Get the public key of the user who created the digital signature
    // and import it into the CSP by using CryptImportKey. This returns
    // a handle to the public key in hPubKey.
    /*if (CryptImportKey(
     hProv,
     pbKeyBlob,
     dwBlobLen,
     0,
     0,
     &hPubKey))
     {
     printf("The key has been imported.\n");
     }
     else
     {
     MyHandleError("Public key import failed.");
     }
     //-------------------------------------------------------------------
     // Create a new hash object.
     if (CryptCreateHash(
     hProv,
     CALG_MD5,
     0,
     0,
     &hHash))
     {
     printf("The hash object has been recreated. \n");
     }
     else
     {
     MyHandleError("Error during CryptCreateHash.");
     }
     //-------------------------------------------------------------------
     // Compute the cryptographic hash of the buffer.
     if (CryptHashData(
     hHash,
     pbBuffer,
     dwBufferLen,
     0))
     {
     printf("The new hash has been created.\n");
     }
     else
     {
     MyHandleError("Error during CryptHashData.");
     }
     //-------------------------------------------------------------------
     // Validate the digital signature.
     if (CryptVerifySignature(
     hHash,
     pbSignature,
     dwSigLen,
     hPubKey,
     NULL,
     0))
     {
     printf("The signature has been verified.\n");
     }
     else
     {
     printf("Signature not validated!\n");
     }
     //-------------------------------------------------------------------
     // Free memory to be used to store signature.
     //-------------------------------------------------------------------
     // Destroy the hash object.
     //-------------------------------------------------------------------
     // Release the provider handle.
     /*if (hProv)
     CryptReleaseContext(hProv, 0);*/
    if (pbSignature) {
        free(pbSignature);
    }
    return string(&buffer[0]);
}
} /* namespace license */
/*
 * CryptoHelperWindows.cpp
 *
 *  Created on: Sep 14, 2014
 *
 */
#include <sstream>
#include <vector>
#include <string>
#include "CryptoHelperWindows.h"
// The RSA public-key key exchange algorithm
#define ENCRYPT_ALGORITHM         CALG_RSA_SIGN
// The high order WORD 0x0200 (decimal 512)
// determines the key length in bits.
#define KEYLENGTH                 0x02000000
#pragma comment(lib, "crypt32.lib")
namespace license {
CryptoHelperWindows::CryptoHelperWindows() {
    m_hCryptProv = NULL;
    m_hCryptKey = NULL;
    if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, 0)) {
        // If the key container cannot be opened, try creating a new
        // container by specifying a container name and setting the
        // CRYPT_NEWKEYSET flag.
        DWORD lastError = GetLastError();
        printf("Error in CryptAcquireContext (1) 0x%08x \n", lastError);
        if (NTE_BAD_KEYSET == lastError) {
            if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
                printf("Warn in CryptAcquireContext: acquiring new user keyset failed 0x%08x, trying less secure mackine keyset \n", GetLastError());
                //maybe access to protected storage disabled. Try with machine keys (less secure)
                if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) {
                    printf("Error in CryptAcquireContext (2) 0x%08x \n", GetLastError());
                    if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)) {
                        printf("Error in CryptAcquireContext (3): acquiring new keyset(machine) failed 0x%08x \n", GetLastError());
                        throw logic_error("");
                    }
                }
            }
        } else {
            printf(" Error in CryptAcquireContext (4) 0x%08x \n", lastError);
            throw logic_error("");
        }
    }
}
/**
 This method calls the CryptGenKey function to get a handle to an
 exportable key-pair. The key-pair is  generated with the RSA public-key
 key exchange algorithm using Microsoft Enhanced Cryptographic Provider.
 */
void CryptoHelperWindows::generateKeyPair() {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    // If the handle to key container is NULL, fail.
    if (m_hCryptProv == NULL)
        throw logic_error("Cryptocontext not correctly initialized");
    // Release a previously acquired handle to key-pair.
    if (m_hCryptKey)
        m_hCryptKey = NULL;
    // Call the CryptGenKey method to get a handle
    // to a new exportable key-pair.
    if (!CryptGenKey(m_hCryptProv, ENCRYPT_ALGORITHM,
    KEYLENGTH | CRYPT_EXPORTABLE, &m_hCryptKey)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error generating keys ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    //double check the key is really generated
    if(m_hCryptKey == NULL) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error generating keys (2)")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
}
/* This method calls the CryptExportKey function to get the Public key
 in a string suitable for C source inclusion.
 */
const string CryptoHelperWindows::exportPublicKey() const {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    DWORD dwBlobLen;
    BYTE *pbKeyBlob = nullptr;
    stringstream ss;
    // If the handle to key container is NULL, fail.
    if (m_hCryptKey == NULL)
        throw logic_error("call GenerateKey first.");
    // This call here determines the length of the key
    // blob.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PUBLICKEYBLOB, 0, nullptr, &dwBlobLen)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error calculating size of public key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    // Allocate memory for the pbKeyBlob.
    if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) {
        throw logic_error(string("Out of memory exporting public key "));
    }
    // Do the actual exporting into the key BLOB.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        delete pbKeyBlob;
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error exporting public key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    } else {
        ss << "\t";
        for (unsigned int i = 0; i < dwBlobLen; i++) {
            if (i != 0) {
                ss << ", ";
                if (i % 10 == 0) {
                    ss << "\\" << endl << "\t";
                }
            }
            ss << to_string(static_cast<long long>(pbKeyBlob[i]));
        }
        delete pbKeyBlob;
    }
    return ss.str();
}
CryptoHelperWindows::~CryptoHelperWindows() {
    if (m_hCryptProv) {
        CryptReleaseContext(m_hCryptProv, 0);
        m_hCryptProv = NULL;
    }
    if (m_hCryptKey)
        m_hCryptKey = NULL;
}
//--------------------------------------------------------------------
// This method calls the CryptExportKey function to get the Private key
// in a byte array. The byte array is allocated on the heap and the size
// of this is returned to the caller. The caller is responsible for releasing // this memory using a delete call.
//--------------------------------------------------------------------
const string CryptoHelperWindows::exportPrivateKey() const {
    HRESULT hr = S_OK;
    DWORD dwErrCode;
    DWORD dwBlobLen;
    BYTE *pbKeyBlob;
    stringstream ss;
    // If the handle to key container is NULL, fail.
    if (m_hCryptKey == NULL)
        throw logic_error(string("call GenerateKey first."));
    // This call here determines the length of the key
    // blob.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PRIVATEKEYBLOB, 0, nullptr, &dwBlobLen)) {
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error calculating size of private key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    }
    // Allocate memory for the pbKeyBlob.
    if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) {
        throw logic_error(string("Out of memory exporting private key "));
    }
    // Do the actual exporting into the key BLOB.
    if (!CryptExportKey(m_hCryptKey,
    NULL, PRIVATEKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) {
        delete pbKeyBlob;
        dwErrCode = GetLastError();
        throw logic_error(
                string("Error exporting private key ")
                        + to_string(static_cast<long long>(dwErrCode)));
    } else {
        ss << "\t";
        for (unsigned int i = 0; i < dwBlobLen; i++) {
            if (i != 0) {
                ss << ", ";
                if (i % 15 == 0) {
                    ss << "\\" << endl << "\t";
                }
            }
            ss << to_string(static_cast<long long>(pbKeyBlob[i]));
        }
        delete pbKeyBlob;
    }
    return ss.str();
}
void CryptoHelperWindows::printHash(HCRYPTHASH *hHash) const {
    BYTE *pbHash;
    DWORD dwHashLen;
    DWORD dwHashLenSize = sizeof(DWORD);
    char *hashStr;
    unsigned int i;
    if (CryptGetHashParam(*hHash, HP_HASHSIZE, (BYTE*) &dwHashLen,
            &dwHashLenSize, 0)) {
        pbHash = (BYTE*) malloc(dwHashLen);
        hashStr = (char*) malloc(dwHashLen * 2 + 1);
        if (CryptGetHashParam(*hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) {
            for (i = 0; i < dwHashLen; i++) {
                sprintf(&hashStr[i * 2], "%02x", pbHash[i]);
            }
            printf("hash To be signed: %s \n", hashStr);
        }
        free(pbHash);
        free(hashStr);
    }
}
const string CryptoHelperWindows::signString(const void *privateKey,
        size_t pklen, const string &license) const {
    BYTE *pbBuffer = (BYTE*) license.c_str();
    const DWORD dwBufferLen = (DWORD) strlen((char*) pbBuffer);
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD strLen;
    //-------------------------------------------------------------------
    // Acquire a cryptographic provider context handle.
    if (!CryptImportKey(m_hCryptProv, (const BYTE*) privateKey, (DWORD) pklen,
            0, 0, &hKey)) {
        throw logic_error(
                string("Error in importing the PrivateKey ")
                        + to_string(static_cast<long long>(GetLastError())));
    }
    //-------------------------------------------------------------------
    // Create the hash object.
    if (CryptCreateHash(m_hCryptProv, CALG_SHA1, 0, 0, &hHash)) {
        printf("Hash object created. \n");
    } else {
        CryptDestroyKey(hKey);
        throw logic_error(string("Error during CryptCreateHash."));
    }
    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    if (CryptHashData(hHash, pbBuffer, dwBufferLen, 0)) {
#ifdef _DEBUG
        printf("Length of data to be hashed: %d \n", dwBufferLen);
        printHash(&hHash);
#endif
    } else {
        throw logic_error(string("Error during CryptHashData."));
    }
    //-------------------------------------------------------------------
    // Determine the size of the signature and allocate memory.
    dwSigLen = 0;
    if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, nullptr, &dwSigLen)) {
        printf("Signature length %d found.\n", dwSigLen);
    } else {
        throw logic_error(string("Error during CryptSignHash."));
    }
    //-------------------------------------------------------------------
    // Allocate memory for the signature buffer.
    if (pbSignature = (BYTE*) malloc(dwSigLen)) {
        printf("Memory allocated for the signature.\n");
    } else {
        throw logic_error(string("Out of memory."));
    }
    //-------------------------------------------------------------------
    // Sign the hash object.
    if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, pbSignature,
            &dwSigLen)) {
        printf("pbSignature is the signature length. %d\n", dwSigLen);
    } else {
        throw logic_error(string("Error during CryptSignHash."));
    }
    //-------------------------------------------------------------------
    // Destroy the hash object.
    CryptDestroyHash(hHash);
    CryptDestroyKey(hKey);
    CryptBinaryToString(pbSignature, dwSigLen,
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &strLen);
    vector<char> buffer(strLen);
    CryptBinaryToString(pbSignature, dwSigLen,
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, &buffer[0], &strLen);
    //-------------------------------------------------------------------
    // In the second phase, the hash signature is verified.
    // This would most often be done by a different user in a
    // separate program. The hash, signature, and the PUBLICKEYBLOB
    // would be read from a file, an email message,
    // or some other source.
    // Here, the original pbBuffer, pbSignature, szDescription.
    // pbKeyBlob, and their lengths are used.
    // The contents of the pbBuffer must be the same data
    // that was originally signed.
    //-------------------------------------------------------------------
    // Get the public key of the user who created the digital signature
    // and import it into the CSP by using CryptImportKey. This returns
    // a handle to the public key in hPubKey.
    /*if (CryptImportKey(
     hProv,
     pbKeyBlob,
     dwBlobLen,
     0,
     0,
     &hPubKey))
     {
     printf("The key has been imported.\n");
     }
     else
     {
     MyHandleError("Public key import failed.");
     }
     //-------------------------------------------------------------------
     // Create a new hash object.
     if (CryptCreateHash(
     hProv,
     CALG_MD5,
     0,
     0,
     &hHash))
     {
     printf("The hash object has been recreated. \n");
     }
     else
     {
     MyHandleError("Error during CryptCreateHash.");
     }
     //-------------------------------------------------------------------
     // Compute the cryptographic hash of the buffer.
     if (CryptHashData(
     hHash,
     pbBuffer,
     dwBufferLen,
     0))
     {
     printf("The new hash has been created.\n");
     }
     else
     {
     MyHandleError("Error during CryptHashData.");
     }
     //-------------------------------------------------------------------
     // Validate the digital signature.
     if (CryptVerifySignature(
     hHash,
     pbSignature,
     dwSigLen,
     hPubKey,
     NULL,
     0))
     {
     printf("The signature has been verified.\n");
     }
     else
     {
     printf("Signature not validated!\n");
     }
     //-------------------------------------------------------------------
     // Free memory to be used to store signature.
     //-------------------------------------------------------------------
     // Destroy the hash object.
     //-------------------------------------------------------------------
     // Release the provider handle.
     /*if (hProv)
     CryptReleaseContext(hProv, 0);*/
    if (pbSignature) {
        free(pbSignature);
    }
    return string(&buffer[0]);
}
} /* namespace license */
src/tools/base_lib/win/CryptoHelperWindows.h
@@ -1,46 +1,46 @@
/*
 * CryptoHelperWindows.h
 *
 *  Created on: Sep 14, 2014
 *
 */
#ifndef CRYPTOHELPERWINDOWS_H_
#define CRYPTOHELPERWINDOWS_H_
//#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#include <tchar.h>
#include <string>
#include "../CryptoHelper.h"
namespace license {
using namespace std;
class CryptoHelperWindows: public CryptoHelper {
private :
    void acquireContext();
    //    Handle to the cryptography provider.
    HCRYPTPROV m_hCryptProv;
    //    Handle to the cryptography key.
    HCRYPTKEY m_hCryptKey;
    void printHash(HCRYPTHASH* hHash) const;
public:
    CryptoHelperWindows();
    virtual void generateKeyPair();
    virtual const string exportPrivateKey() const;
    virtual const string exportPublicKey() const;
    virtual const string signString(const void* privateKey, size_t pklen,
            const string& license) const;
    virtual ~CryptoHelperWindows();
};
} /* namespace license */
#endif /* CRYPTOHELPERWINDOWS_H_ */
/*
 * CryptoHelperWindows.h
 *
 *  Created on: Sep 14, 2014
 *
 */
#ifndef CRYPTOHELPERWINDOWS_H_
#define CRYPTOHELPERWINDOWS_H_
//#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#include <tchar.h>
#include <string>
#include "../CryptoHelper.h"
namespace license {
using namespace std;
class CryptoHelperWindows: public CryptoHelper {
private :
    void acquireContext();
    //    Handle to the cryptography provider.
    HCRYPTPROV m_hCryptProv;
    //    Handle to the cryptography key.
    HCRYPTKEY m_hCryptKey;
    void printHash(HCRYPTHASH* hHash) const;
public:
    CryptoHelperWindows();
    virtual void generateKeyPair();
    virtual const string exportPrivateKey() const;
    virtual const string exportPublicKey() const;
    virtual const string signString(const void* privateKey, size_t pklen,
            const string& license) const;
    virtual ~CryptoHelperWindows();
};
} /* namespace license */
#endif /* CRYPTOHELPERWINDOWS_H_ */
src/tools/license-generator/CMakeLists.txt
@@ -10,6 +10,7 @@
target_link_libraries(
     license_generator_lib
     tools_base
     base
     licensecc_static
     $<$<CONFIG:Debug>:${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG}>
     $<$<NOT:$<CONFIG:Debug>>:${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE}>     
src/tools/license-generator/license-generator.cpp
@@ -1,32 +1,40 @@
#include <build_properties.h>
#include <private-key.h>
#include "license-generator.h"
#include "../base_lib/CryptoHelper.h"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string.h>
#include <iostream>
#include <string.h>
#include <boost/date_time.hpp>
#include <iterator>
#include <map>
#include <memory>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/unordered_map.hpp>
#include <boost/assign.hpp>
#include <fstream>
#include <regex>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
namespace bt = boost::posix_time;
#include <private-key.h>
#include <build_properties.h>
#include "../../library/base/base64.h"
#include "../base_lib/CryptoHelper.h"
//namespace fs = boost::filesystem;
//namespace bt = boost::posix_time;
namespace po = boost::program_options;
using namespace std;
namespace license {
void LicenseGenerator::printHelp(const char* prog_name,
        const po::options_description& options) {
void LicenseGenerator::printHelp(const char *prog_name,
        const po::options_description &options) {
    cout << endl;
    cout << prog_name << " Version " << PROJECT_VERSION << endl << ". Usage:"
            << endl;
@@ -40,43 +48,41 @@
po::options_description LicenseGenerator::configureProgramOptions() {
    po::options_description common("General options");
    common.add_options()
        ("help,h", "print help message and exit.")
        ("verbose,v", "print more information.")
        ("output,o", po::value<string>(), "Output file name. If not specified the "
            "license will be printed in standard output")
        ;
    common.add_options()("help,h", "print help message and exit.") //
    ("verbose,v", "print more information.")//
    ("output,o", po::value<string>(), "Output file name. If not specified the "
            "license will be printed to standard output");
    po::options_description licenseGeneration("License Generation");
    licenseGeneration.add_options()
        ("private_key,p", po::value<string>(),
    licenseGeneration.add_options()("private_key,p", po::value<string>(),
            "Specify an alternate file for the primary key to be used. "
                    "If not specified the internal primary key will be used.")
        ("begin_date,b", po::value<string>(),
                    "If not specified the internal primary key will be used.")(
            "begin_date,b", po::value<string>(),
            "Specify the start of the validity for this license. "
                    " Format YYYYMMDD. If not specified defaults to today")
        ("expire_date,e", po::value<string>(),
                    " Format YYYYMMDD. If not specified defaults to today")(
            "expire_date,e", po::value<string>(),
            "Specify the expire date for this license. "
                    " Format YYYYMMDD. If not specified the license won't expire")
        ("client_signature,s", po::value<string>(),
                    " Format YYYYMMDD. If not specified the license won't expire")(
            "client_signature,s", po::value<string>(),
            "The signature of the pc that requires the license. "
                    "It should be in the format XXXX-XXXX-XXXX-XXXX."
                    " If not specified the license "
                    "won't be linked to a specific pc.")
        ("start_version,t", po::value<unsigned int>()->default_value(0
                    "won't be linked to a specific pc.")("start_version,t",
            po::value<unsigned int>()->default_value(0
            /*FullLicenseInfo.UNUSED_SOFTWARE_VERSION*/, "All Versions"),
            "Specify the first version of the software this license apply to.")
        ("end_version,n", po::value<unsigned int>()->default_value(0
            "Specify the first version of the software this license apply to.")(
            "end_version,n", po::value<unsigned int>()->default_value(0
            /*FullLicenseInfo.UNUSED_SOFTWARE_VERSION*/, "All Versions"),
            "Specify the last version of the software this license apply to.")
        ("extra_data,x", po::value<string>(), "Specify extra data to be included into the license")
        ;
            "Specify the last version of the software this license apply to.")(
            "extra_data,x", po::value<string>(),
            "Specify extra data to be included into the license");
    po::options_description visibleOptions;
    visibleOptions.add(common).add(licenseGeneration);
    return visibleOptions;
}
vector<FullLicenseInfo> LicenseGenerator::parseLicenseInfo(
        const po::variables_map& vm) {
        const po::variables_map &vm) {
    string begin_date = FullLicenseInfo::UNUSED_TIME;
    string end_date = FullLicenseInfo::UNUSED_TIME;
    if (vm.count("expire_date")) {
@@ -108,13 +114,14 @@
    if (vm.count("client_signature")) {
        client_signature = vm["client_signature"].as<string>();
        cout << "cli sig:" << client_signature;
        regex e("[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}");
        regex e(
                "[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}");
        cout << "\nregex:";
        if (!regex_match(client_signature, e)) {
            cerr << endl << "Client signature not recognized: "
                << client_signature
                << " Please enter a valid signature in format XXXX-XXXX-XXXX-XXXX"
                << endl;
                    << client_signature
                    << " Please enter a valid signature in format XXXX-XXXX-XXXX-XXXX"
                    << endl;
            exit(2);
        }
    }
@@ -142,18 +149,32 @@
    return licInfo;
}
void LicenseGenerator::generateAndOutputLicenses(const po::variables_map& vm,
        ostream& outputFile) {
void LicenseGenerator::generateAndOutputLicenses(const po::variables_map &vm,
        ostream &outputFile) {
    vector<FullLicenseInfo> licenseInfo = parseLicenseInfo(vm);
    const unique_ptr<CryptoHelper> helper = CryptoHelper::getInstance();
    const unsigned char pkey[] = PRIVATE_KEY;
    const size_t len = sizeof(pkey);
    for (auto it = licenseInfo.begin(); it != licenseInfo.end(); ++it) {
        const string license = it->printForSign();
        const string signature = helper->signString((const void *)pkey,len,license);
        const string signature = helper->signString((const void*) pkey, len,
                license);
        it->license_signature = signature;
        it->printAsIni(outputFile);
    }
}
void LicenseGenerator::generateB64Licenses(const po::variables_map &vm,
        ostream &outputFile) {
    std::ostringstream tempStream;
    generateAndOutputLicenses(vm, tempStream);
    std::string str = tempStream.str();
    const char *chr = str.c_str();
    int finalLenght;
    char *encoded = base64(chr, str.length(), &finalLenght);
    outputFile.write(encoded, finalLenght);
    free(encoded);
}
int LicenseGenerator::generateLicense(int argc, const char **argv) {
@@ -183,13 +204,21 @@
        fstream ofstream(fname, std::ios::out | std::ios::app);
        if (!ofstream.is_open()) {
            cerr << "can't open file [" << fname << "] for output." << endl
                    << " error: " << strerror( errno);
                    << " error: " << strerror(errno) << endl;
            exit(3);
        }
        generateAndOutputLicenses(vm, ofstream);
        if (vm.count("base64")) {
            generateB64Licenses(vm, ofstream);
        } else {
            generateAndOutputLicenses(vm, ofstream);
        }
        ofstream.close();
    } else {
        generateAndOutputLicenses(vm, cout);
        if (vm.count("base64")) {
            generateB64Licenses(vm, cout);
        } else {
            generateAndOutputLicenses(vm, cout);
        }
    }
    return 0;
}
@@ -197,22 +226,24 @@
const std::string formats[] = { "%4u-%2u-%2u", "%4u/%2u/%2u", "%4u%2u%2u" };
const size_t formats_n = 3;
string LicenseGenerator::normalize_date(const std::string& sDate) {
    if(sDate.size()<8)
string LicenseGenerator::normalize_date(const std::string &sDate) {
    if (sDate.size() < 8)
        throw invalid_argument("Date string too small for known formats");
    unsigned int year, month, day;
    bool found = false;
    for (size_t i = 0; i < formats_n && !found; ++i) {
        const int chread = sscanf(sDate.c_str(),formats[i].c_str(),&year,&month,&day);
        if(chread==3) {
        const int chread = sscanf(sDate.c_str(), formats[i].c_str(), &year,
                &month, &day);
        if (chread == 3) {
            found = true;
            break;
        }
    }
    if(!found)
    if (!found)
        throw invalid_argument("Date string did not match a known format");
    ostringstream oss;
    oss << year << "-" << setfill('0') << std::setw(2) << month << "-" << setfill('0') << std::setw(2) << day;
    oss << year << "-" << setfill('0') << std::setw(2) << month << "-"
            << setfill('0') << std::setw(2) << day;
    return oss.str();
}
}
src/tools/license-generator/license-generator.h
@@ -2,14 +2,13 @@
 * LicenseSigner.h
 *
 *  Created on: Apr 6, 2014
 *
 *
 */
#ifndef LICENSE_GENERATOR_H_
#define LICENSE_GENERATOR_H_
#include <boost/program_options.hpp>
#include "../../library/LicenseReader.hpp"
namespace license {
@@ -22,12 +21,15 @@
class LicenseGenerator {
private:
    LicenseGenerator();
    static void printHelp(const char* prog_name, const po::options_description& options);
    static po::options_description configureProgramOptions();
    static vector<FullLicenseInfo> parseLicenseInfo(const po::variables_map& vm);
    static std::vector<FullLicenseInfo> parseLicenseInfo(const po::variables_map& vm);
    static void generateAndOutputLicenses(const po::variables_map& vm,
            ostream& outputFile);
    static string normalize_date(const std::string& s);
            std::ostream& outputFile);
    static void generateB64Licenses(const po::variables_map& vm,
            std::ostream& outputFile);
    static std::string normalize_date(const std::string& s);
public:
    /**
     * Available options:
test/functional/CMakeLists.txt
@@ -8,12 +8,12 @@
)
add_executable(
 standard_license_test
 test_standard_license
 standard-license_test.cpp
)
target_link_libraries(
 standard_license_test
 test_standard_license
 licensecc_static
 license_generator_snippet
 ${Boost_LIBRARIES}
@@ -46,11 +46,11 @@
IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING)
#binfmt_misc doesn't work in my system :(
    ADD_TEST(NAME standard_license_test COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/standard_license_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_standard_license COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_date COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_volid COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ELSE()
    ADD_TEST(NAME standard_license_test COMMAND standard_license_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_standard_license COMMAND test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_date COMMAND test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    ADD_TEST(NAME test_volid COMMAND test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ENDIF()
test/functional/date_test.cpp
@@ -24,10 +24,9 @@
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    const EVENT_TYPE result = acquire_license("TEST", licenseLocation,
    licenseLocation.licenseData = "";
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation,
            &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, true);
@@ -44,10 +43,10 @@
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    const EVENT_TYPE result = acquire_license("TEST", licenseLocation,
    licenseLocation.licenseData = nullptr;
    BOOST_TEST_MESSAGE("before acquire license");
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation,
            &license);
    BOOST_CHECK_EQUAL(result, PRODUCT_EXPIRED);
    BOOST_CHECK_EQUAL(license.has_expiry, true);
test/functional/hijiaking_test.cpp
@@ -23,7 +23,7 @@
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule=false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    licenseLocation.licenseData = "";
    EVENT_TYPE result = acquire_license("TEST",
            licenseLocation, & license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
test/functional/standard-license_test.cpp
@@ -1,6 +1,5 @@
#define BOOST_TEST_MODULE standard_license_test
//#define BOOST_TEST_MAIN
//#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE test_standard_license
#include <boost/test/unit_test.hpp>
#include "../../src/tools/license-generator/license-generator.h"
#include "../../src/library/api/license++.h"
@@ -8,12 +7,12 @@
#include <boost/filesystem.hpp>
#include "../../src/library/ini/SimpleIni.h"
#include "generate-license.h"
#include "../../src/library/base/FileUtils.hpp"
namespace test {
namespace fs = boost::filesystem;
using namespace license;
using namespace std;
namespace test {
BOOST_AUTO_TEST_CASE( standard_lic_file ) {
    const string licLocation(PROJECT_TEST_TEMP_DIR "/standard_license.lic");
@@ -22,10 +21,29 @@
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    const EVENT_TYPE result = acquire_license("TEST", licenseLocation,
    licenseLocation.licenseData = nullptr;
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation,
            &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
}
/**
 * Pass the license data to the application.
 */
BOOST_AUTO_TEST_CASE( b64_environment_variable ) {
    const string licLocation(PROJECT_TEST_TEMP_DIR "/standard_env_license.lic");
    const vector<string> extraArgs;
    generate_license(licLocation, extraArgs);
    const string licensestr(license::get_file_contents(licLocation.c_str(), MAX_LICENSE_LENGTH));
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.licenseFileLocation = nullptr;
    licenseLocation.licenseData = licensestr.c_str();
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation,
            &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
@@ -39,10 +57,9 @@
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    const EVENT_TYPE result = acquire_license("TEST", licenseLocation,
    licenseLocation.licenseData = "";
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation,
            &license);
    BOOST_CHECK_EQUAL(result, IDENTIFIERS_MISMATCH);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
test/functional/volid_test.cpp
@@ -35,10 +35,9 @@
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.openFileNearModule = false;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.environmentVariableName = "";
    const EVENT_TYPE result = acquire_license("TEST", licenseLocation, &license);
    licenseLocation.licenseData = "";
    const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
    BOOST_CHECK_EQUAL(license.linked_to_pc, true);
test/library/CMakeLists.txt
@@ -51,4 +51,22 @@
    ADD_TEST(NAME test_license_locator COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_license_locator)
ELSE()
    ADD_TEST(NAME test_license_locator COMMAND test_license_locator)
ENDIF()
### LicenseLocator tests
add_executable(
 test_event_registry
 EventRegistry_test.cpp
)
target_link_libraries(
 test_event_registry
 base
 ${Boost_LIBRARIES}
)
IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING)
    ADD_TEST(NAME test_event_registry COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_event_registry)
ELSE()
    ADD_TEST(NAME test_event_registry COMMAND test_event_registry)
ENDIF()
test/library/EventRegistry_test.cpp
New file
@@ -0,0 +1,41 @@
#define BOOST_TEST_MODULE "test_event_registry"
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <boost/test/unit_test.hpp>
#include <stdlib.h>
#include <cstdio>
#include <build_properties.h>
#include "../../src/library/base/EventRegistry.h"
namespace test {
using namespace std;
using namespace license;
/**
 * The error reported is for the license that advanced most in the validation process
 *
 */
BOOST_AUTO_TEST_CASE( test_most_advanced_license_error ) {
    EventRegistry er;
    er.addEvent(LICENSE_SPECIFIED, "lic2");
    er.addEvent(LICENSE_FOUND, "lic1");
    er.addEvent(LICENSE_CORRUPTED, "lic1");
    er.turnWarningsIntoErrors();
    const AuditEvent *event = er.getLastFailure();
    BOOST_CHECK_MESSAGE(event != nullptr, "An error is detected");
    BOOST_CHECK_MESSAGE(string("lic1") == event->license_reference, "Error is for lic1");
    BOOST_CHECK_MESSAGE(LICENSE_CORRUPTED == event->event_type, "Error is for LICENSE_CORRUPTED");
}
}  //namespace test
test/library/LicenseLocator_test.cpp
@@ -14,6 +14,8 @@
#include <cstdio>
#include <build_properties.h>
#include "../../src/library/os/os.h"
#include "../../src/library/base/EventRegistry.h"
#include "../../src/library/locate/ApplicationFolder.hpp"
#include "../../src/library/locate/EnvironmentVarLocation.hpp"
@@ -69,13 +71,13 @@
        license::EventRegistry registry;
        ApplicationFolder applicationFolder;
        vector<string> licenseInfos = applicationFolder.licenseLocations(registry);
        vector<string> licenseInfos = applicationFolder.license_locations(registry);
        BOOST_CHECK(registry.isGood());
        BOOST_REQUIRE_EQUAL(1, licenseInfos.size());
        string currentLocation = licenseInfos[0];
        BOOST_CHECK_MESSAGE(equivalent(path(referenceLicenseFileName),path(currentLocation)),
            "file " +currentLocation + "found at expected location");
        string licenseRealContent = applicationFolder.retrieveLicense(
        string licenseRealContent = applicationFolder.retrieve_license_content(
            currentLocation);
        src.seekg(0, ios::beg);
        std::string referenceContent((std::istreambuf_iterator<char>(src)),
@@ -100,31 +102,33 @@
    std::string referenceContent((std::istreambuf_iterator<char>(src)),
            std::istreambuf_iterator<char>());
    license::EventRegistry registry;
    ExternalDefinition externalDefinition(applicationDefinedString);
    vector<string> licenseInfos = externalDefinition.licenseLocations(registry);
    const LicenseLocation licLocation({applicationDefinedString,nullptr});
    ExternalDefinition externalDefinition(&licLocation);
    vector<string> licenseInfos = externalDefinition.license_locations(registry);
    BOOST_CHECK(registry.isGood());
    BOOST_CHECK_EQUAL(1, licenseInfos.size());
    string currentLocation = licenseInfos[0];
    BOOST_CHECK_MESSAGE(string(MOCK_LICENSE).compare(currentLocation) == 0,
            "file found at expected location");
    string licenseRealContent = externalDefinition.retrieveLicense(
    string licenseRealContent = externalDefinition.retrieve_license_content(
            currentLocation);
    BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0,
            "File content is same");
}
/**
 * The license file doesn't exist. Chech that the locator reports the right error
 * The license file doesn't exist. Check that the locator reports the right error
 */
BOOST_AUTO_TEST_CASE( external_definition_not_found ) {
    const char *applicationDefinedString = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
    license::EventRegistry registry;
    ExternalDefinition externalDefinition(applicationDefinedString);
    vector<string> licenseInfos = externalDefinition.licenseLocations(registry);
    const LicenseLocation licLocation({applicationDefinedString,nullptr});
    ExternalDefinition externalDefinition(&licLocation);
    vector<string> licenseInfos = externalDefinition.license_locations(registry);
    BOOST_CHECK_MESSAGE(registry.isGood(),
            "No fatal error for now, only warnings");
    registry.turnEventIntoError(LICENSE_FILE_NOT_FOUND);
    registry.turnWarningsIntoErrors();
    BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected");
    BOOST_CHECK_EQUAL(0, licenseInfos.size());
    BOOST_CHECK_MESSAGE(
@@ -152,23 +156,18 @@
    license::EventRegistry registry;
    EnvironmentVarLocation envVarLocationStrategy;
    vector<string> licenseInfos = envVarLocationStrategy.licenseLocations(
    vector<string> licenseInfos = envVarLocationStrategy.license_locations(
            registry);
    BOOST_CHECK(registry.isGood());
    BOOST_CHECK_EQUAL(1, licenseInfos.size());
    string currentLocation = licenseInfos[0];
    BOOST_CHECK_MESSAGE(string(MOCK_LICENSE).compare(currentLocation) == 0,
            "file found at expected location");
    string licenseRealContent = envVarLocationStrategy.retrieveLicense(
    string licenseRealContent = envVarLocationStrategy.retrieve_license_content(
            currentLocation);
    BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0,
            "File content is same");
#ifdef _WIN32
    _putenv_s(LICENSE_LOCATION_ENV_VAR, "");
#else
    unsetenv(LICENSE_LOCATION_ENV_VAR);
#endif
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
}
/**
@@ -177,47 +176,36 @@
BOOST_AUTO_TEST_CASE( environment_var_location_not_found ) {
    const char *environment_variable_value =
    PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
#ifdef _WIN32
    _putenv_s(LICENSE_LOCATION_ENV_VAR, environment_variable_value);
#else
    setenv(LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1);
#endif
    SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value);
    license::EventRegistry registry;
    EnvironmentVarLocation envVarLocationStrategy;
    vector<string> licenseInfos = envVarLocationStrategy.licenseLocations(
    vector<string> licenseInfos = envVarLocationStrategy.license_locations(
            registry);
    BOOST_CHECK_MESSAGE(registry.isGood(),
            "No fatal error for now, only warnings");
    registry.turnEventIntoError(LICENSE_FILE_NOT_FOUND);
    registry.turnWarningsIntoErrors();
    BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected");
    BOOST_CHECK_EQUAL(0, licenseInfos.size());
    BOOST_CHECK_MESSAGE(
            registry.getLastFailure()->event_type == LICENSE_FILE_NOT_FOUND,
            "Error detected");
#ifdef _WIN32
    _putenv_s(LICENSE_LOCATION_ENV_VAR, "");
#else
    unsetenv(LICENSE_LOCATION_ENV_VAR);
#endif
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
}
/**
 * The license file doesn't exist. Check that the locator reports the right error
 */
BOOST_AUTO_TEST_CASE( environment_var_location_not_defined ) {
#ifdef _WIN32
    _putenv_s(LICENSE_LOCATION_ENV_VAR, "");
#else
    unsetenv(LICENSE_LOCATION_ENV_VAR);
#endif
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
    license::EventRegistry registry;
    EnvironmentVarLocation environmentVarLocation;
    vector<string> licenseInfos = environmentVarLocation.licenseLocations(
    vector<string> licenseInfos = environmentVarLocation.license_locations(
            registry);
    BOOST_CHECK_MESSAGE(registry.isGood(),
            "No fatal error for now, only warnings");
    registry.turnEventIntoError(ENVIRONMENT_VARIABLE_NOT_DEFINED);
    registry.turnWarningsIntoErrors();
    BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected");
    BOOST_CHECK_EQUAL(0, licenseInfos.size());
    BOOST_CHECK_MESSAGE(
test/library/LicenseReader_test.cpp
@@ -1,4 +1,14 @@
#define BOOST_TEST_MODULE "test_license_reader"
#include <boost/assert.hpp>
#include <boost/test/tools/old/interface.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <iostream>
#include <vector>
#include "../../src/library/api/datatypes.h"
#include "../../src/library/base/EventRegistry.h"
#include "../../src/library/os/os.h"
#include <boost/test/unit_test.hpp>
#include <stdlib.h>
@@ -6,13 +16,17 @@
#include <build_properties.h>
#include "../../src/library/LicenseReader.hpp"
namespace test {
using namespace license;
using namespace std;
/**
 * Read license at fixed location
 */
BOOST_AUTO_TEST_CASE( read_single_file ) {
    const char *licLocation = PROJECT_TEST_SRC_DIR  "/library/test_reader.ini";
    const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    const LicenseLocation location = { licLocation, nullptr, false };
    LicenseReader licenseReader(location);
    const LicenseLocation location = { licLocation, nullptr };
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PrODUCT",
            licenseInfos);
@@ -20,11 +34,14 @@
    BOOST_CHECK_EQUAL(1, licenseInfos.size());
}
/**
 * Test the error return if the product code is not found in the license
 */
BOOST_AUTO_TEST_CASE( product_not_licensed ) {
    const char *licLocation =
    PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    const LicenseLocation location = { licLocation, nullptr, false };
    LicenseReader licenseReader(location);
    const LicenseLocation location = { licLocation, nullptr };
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT-NOT",
            licenseInfos);
@@ -35,11 +52,14 @@
            registry.getLastFailure()->event_type);
}
/**
 * Test the error code if the license file is specified but doesn't exists
 */
BOOST_AUTO_TEST_CASE( file_not_found ) {
    const char *licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini";
    //const char * envName = "MYVAR";
    const LicenseLocation location = { licLocation, nullptr, false };
    LicenseReader licenseReader(location);
    const LicenseLocation location = { licLocation, nullptr };
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT",
            licenseInfos);
@@ -50,10 +70,13 @@
            registry.getLastFailure()->event_type);
}
/**
 * Test the error code if the license default environment variable isn't specified
 */
BOOST_AUTO_TEST_CASE( env_var_not_defined ) {
    const char *envName = "MYVAR";
    const LicenseLocation location = { nullptr, envName, false };
    LicenseReader licenseReader(location);
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
    const LicenseLocation location = { nullptr, nullptr };
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT",
            licenseInfos);
@@ -64,3 +87,26 @@
            registry.getLastFailure()->event_type);
}
/**
 * Test the error code if the license default environment variable is
 * specified but points to a non existent file.
 */
BOOST_AUTO_TEST_CASE( env_var_point_to_wrong_file ) {
    const char *environment_variable_value =
    PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
    SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value)
    const LicenseLocation location = { nullptr, nullptr };
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT",
            licenseInfos);
    cout << registry << endl;
    BOOST_CHECK(!registry.isGood());
    BOOST_CHECK_EQUAL(0, licenseInfos.size());
    BOOST_ASSERT(registry.getLastFailure()!=NULL);
    BOOST_CHECK_EQUAL(LICENSE_FILE_NOT_FOUND,
            registry.getLastFailure()->event_type);
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
}
} /* namespace test*/