#pragma once #include #include #include "except.h" #include "template.h" #include "generator.h" #include "validator.h" #include "ntpclient.h" #include "uniconv.h" #include "license.h" #include "licensevalidationargs.h" #include "licensevalidationresult.h" #include #ifdef _WIN32 #include #include #else #include #endif using namespace std; // these methods are compiler workarounds to eliminate circular references. // They only call the corresponding LicensingClient::... methods // GCC complains of cross-references between LicensingClientImpl and LicensingClientT const wchar_t * GetCurrentHardwareIdW(void *); const char * GetCurrentHardwareIdA(void *); bool MatchCurrentHardwareIdW(void *, const wchar_t *); bool MatchCurrentHardwareIdA(void *, const char *); class LicensingClientImpl { public: LicensingClientImpl(void * licensingClient, bool usesWideChar) { licenseKeyValidationDataLen = 0; licenseTemplateId.clear(); parentLicensingClient = licensingClient; parentUsesWideChar = usesWideChar; timeValidationMethod = PREFER_INTERNET_TIME; m_licenseValidityDays = 0; // GetCurrentHardwareIdCallback = GetCurrentHardwareId; // MatchCurrentHardwareIdCallback = MatchCurrentHardwareId; } void SetLicenseTemplate(const LicenseTemplateImpl* tmpl) { licenseTemplate = tmpl; } void SetLicenseKey(const char * key) { licenseKey = key; } void SetActivationKey(const char * key) { activationKey = key; } const char * GetActivationKey() { return activationKey.c_str(); } void SetHardwareId(const char * hwid) { hardwareId = hwid; } const char * GetHardwareId() { return hardwareId.c_str(); } void SetLicenseTemplateId(const char * templateId) { licenseTemplateId = templateId; } const char * GetLicenseTemplateId() { return licenseTemplateId.c_str(); } void SetLicenseKeyValidationData(const void* data, unsigned len) { licenseKeyValidationData.resize(len); memcpy(licenseKeyValidationData.data(), data, len); licenseKeyValidationDataLen = len; } LicenseTemplateImpl * CreateActivationTemplate() { LicenseTemplateImpl * tmpl = new LicenseTemplateImpl(); tmpl->SetCharactersPerGroup(licenseTemplate->GetCharactersPerGroup()); tmpl->SetNumberOfGroups(licenseTemplate->GetNumberOfGroups()); tmpl->SetGroupSeparator(licenseTemplate->GetGroupSeparator()); //activationKeyTemplate.SetDataSize(t.GetDataSize()); tmpl->SetSignatureSize(licenseTemplate->GetSignatureSize()); tmpl->SetEncoding(licenseTemplate->GetEncoding()); tmpl->SetPublicKeyCertificate(licenseTemplate->GetPublicKeyCertificate()); int keyLen = tmpl->GetNumberOfGroups() * tmpl->GetCharactersPerGroup() + (tmpl->GetNumberOfGroups() - 1) * strlen(tmpl->GetGroupSeparator()); int hwidLen = 29; if (hardwareId.length() > 0) hwidLen = hardwareId.length(); tmpl->SetDataSize(tmpl->GetCharactersPerGroup() * tmpl->GetNumberOfGroups() * tmpl->GetEncoding() - tmpl->GetSignatureSize()); tmpl->SetValidationDataSize((keyLen + hwidLen ) * 8 + licenseTemplate->GetValidationDataSize()); tmpl->AddDataField("ExpirationDate", FIELD_TYPE_RAW, 16, 0); tmpl->AddValidationField("LicenseKey", FIELD_TYPE_STRING, keyLen * 8, 0); tmpl->AddValidationField("HardwareId", FIELD_TYPE_STRING, hwidLen * 8, keyLen * 8); if (!licenseKeyValidationData.empty()) { tmpl->AddValidationField("LicenseKeyValidationData", FIELD_TYPE_RAW, licenseKeyValidationDataLen * 8, (keyLen + hwidLen) * 8); } if (licensingServiceUrl.empty()) tmpl->SetLicensingServiceUrl(licenseTemplate->GetLicensingServiceUrl()); else tmpl->SetLicensingServiceUrl(licensingServiceUrl.c_str()); if (licenseTemplateId.empty()) tmpl->SetTemplateId(licenseTemplate->GetTemplateId()); else tmpl->SetTemplateId(licenseTemplateId.c_str()); return tmpl; } bool ValidateHardwareId() { if (!MatchCurrentHardwareIdCallback(hardwareId.c_str())) { activationStatus = STATUS_INVALID_HARDWARE_ID; return false; } return true; } bool ValidateActivationKey(LicenseTemplateImpl* activationTemplate = nullptr, bool validateExpirationDate = true) { bool ownActivationTemplate = false; try { if (!activationTemplate) { activationTemplate = CreateActivationTemplate(); ownActivationTemplate = true; } KeyValidatorImpl validator(activationTemplate); validator.SetValidationData("LicenseKey", licenseKey.c_str()); validator.SetValidationData("HardwareId", hardwareId.c_str()); if (!licenseKeyValidationData.empty()) validator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), (activationTemplate->GetValidationDataSize() + 7) >> 3); try { validator.SetKey(activationKey.c_str()); } catch (Exception * ex) { ex->Destroy(); activationStatus = STATUS_INVALID_ACTIVATION_KEY; if (ownActivationTemplate) delete activationTemplate; return false; } if (!validator.IsKeyValid()) { activationStatus = STATUS_INVALID_ACTIVATION_KEY; if (ownActivationTemplate) delete activationTemplate; return false; } unsigned char rawKeyData[2]; int rawKeyDataBits = 16; validator.QueryKeyData("ExpirationDate", rawKeyData, &rawKeyDataBits); unsigned short keyData = (unsigned short)(((unsigned short)rawKeyData[0]) << 8 | rawKeyData[1]); memset(&licenseExpirationTime, 0, sizeof(licenseExpirationTime)); if (keyData != 0) { licenseExpirationTime.tm_year = (2000 + (keyData >> 9)) - 1900; licenseExpirationTime.tm_mon = ((keyData & 0x01FF) >> 5) - 1; licenseExpirationTime.tm_mday = keyData & 0x001F; if (!validateExpirationDate) { if (ownActivationTemplate) delete activationTemplate; return true; } time_t currentTime; if (timeValidationMethod != USE_LOCAL_TIME) { currentTime = NTPClient::GetCurrentTimeUTC(); if (currentTime == 0) // if couldn't obtain internet time { if (timeValidationMethod == USE_INTERNET_TIME) // internet time was mandatory { activationStatus = STATUS_NET_ERROR; if (ownActivationTemplate) delete activationTemplate; return false; } // fallback to local time currentTime = time(NULL); } } else currentTime = time(NULL); double diffSeconds = difftime(mktime(&licenseExpirationTime), currentTime); if (diffSeconds < 0) { m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() - (int)(((time_t)(-diffSeconds) + 86400 - 1) / 86400); if (m_licenseValidityDays < 0) m_licenseValidityDays = 0; activationStatus = STATUS_LICENSE_EXPIRED; if (ownActivationTemplate) delete activationTemplate; return false; } else m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() + (int)(((time_t)diffSeconds + 86400 - 1) / 86400); } else m_licenseValidityDays = -1; if (ownActivationTemplate) delete activationTemplate; return true; } catch (...) { if (ownActivationTemplate && activationTemplate) delete activationTemplate; throw; } } bool IsLicenseValid() { activationStatus = STATUS_GENERIC_ERROR; try { if (ValidateHardwareId() && ValidateActivationKey()) { activationStatus = STATUS_SUCCESS; return true; } else return false; } catch (Exception * ex) { ex->Destroy(); activationStatus = STATUS_GENERIC_ERROR; return false; } catch (...) { activationStatus = STATUS_GENERIC_ERROR; return false; } } LicenseValidationResultImpl& ValidateLicense(LicenseValidationArgsImpl * args) { const LicenseImpl * license = args->GetLicense(); const char * lk = args->GetLicenseKey(); licenseKey = (lk) ? lk : ""; if (license == NULL && licenseKey.length() == 0) throw new LicensingException(STATUS_GENERIC_ERROR, "either a license or a license key must be provided"); if (license == NULL) { try { KeyValidatorImpl keyValidator; keyValidator.SetKeyTemplate(licenseTemplate); keyValidator.SetKey(lk); if (licenseTemplate->GetValidationDataSize() > 0) { int fieldType, fieldSize, fieldOffset; for (std::list::iterator iter = args->m_licenseKeyValidationData.begin(); iter != args->m_licenseKeyValidationData.end(); iter++) { if (!licenseTemplate->GetValidationField(iter->name.c_str(), &fieldType, &fieldSize, &fieldOffset)) throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key validation data is invalid"); switch (fieldType) { case FIELD_TYPE_INTEGER: keyValidator.SetValidationData(iter->name.c_str(), iter->intValue); break; case FIELD_TYPE_STRING: keyValidator.SetValidationData(iter->name.c_str(), iter->stringValue.c_str()); break; case FIELD_TYPE_DATE13: case FIELD_TYPE_DATE14: case FIELD_TYPE_DATE16: keyValidator.SetValidationData(iter->name.c_str(), iter->dateValue.year, iter->dateValue.month, iter->dateValue.day); break; case FIELD_TYPE_RAW: // keyValidator.SetValidationData(iter->name.c_str(), &(iter->value.binaryValue[0]), iter->value.binaryValue.size); break; default: break; } } licenseKeyValidationDataLen = (licenseTemplate->GetValidationDataSize() + 7) >> 3; licenseKeyValidationData.resize(licenseKeyValidationDataLen); keyValidator.QueryValidationData(NULL, licenseKeyValidationData.data(), &licenseKeyValidationDataLen); } if (!keyValidator.IsKeyValid()) { throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key is not valid"); } AcquireLicense(); } catch (LicensingException * ex) { if (ex->GetCode() == STATUS_PAYMENT_REQUIRED) { m_licenseValidationResult.SetPaymentRequired(true); ex->Destroy(); } else throw; } } else { licenseKey = license->GetLicenseKey(); hardwareId = license->GetHardwareId(); activationKey = license->GetActivationKey(); const void* buf; int len; license->GetLicenseKeyValidationData(&buf, &len); if (buf && (len > 0)) SetLicenseKeyValidationData(buf, (unsigned int)len); if (ValidateActivationKey(NULL, true)) { m_licenseValidationResult.SetLicenseValid(true); m_licenseValidationResult.SetPaymentRequired(false); m_licenseValidationResult.SetLicenseExpired(false); m_licenseValidationResult.SetLicense(NULL); return m_licenseValidationResult; } else { if (activationStatus == STATUS_LICENSE_EXPIRED) { m_licenseValidationResult.SetLicenseExpired(true); } if ((activationStatus == STATUS_LICENSE_EXPIRED) && (m_licenseValidityDays > 0) && license->IsLease()) { try { AcquireLicense(); m_licenseValidationResult.SetLicenseExpired(false); } catch (LicensingException * ex) { if (ex->GetCode() == STATUS_PAYMENT_REQUIRED) { m_licenseValidationResult.SetPaymentRequired(true); ex->Destroy(); } else throw; } } } } if (licenseExpirationTime.tm_year > 0) { m_licenseValidationResult.SetLicenseExpirationDate( 1900 + licenseExpirationTime.tm_year, 1 + licenseExpirationTime.tm_mon, licenseExpirationTime.tm_mday); } else { m_licenseValidationResult.SetLicenseExpirationDate(0, 0, 0); } return m_licenseValidationResult; } void AcquireLicense() { if (hardwareId.empty()) hardwareId = (parentLicensingClient) ? GetCurrentHardwareIdCallback() : GetCurrentHardwareId(); unique_ptr activationTemplate(CreateActivationTemplate()); const char * templateId = activationTemplate->GetTemplateId(); if (templateId != NULL && templateId[0] != '\0') { char params[64] = "ProductId="; sprintf(params + sizeof("ProductId"), "%s", activationTemplate->GetTemplateId()); activationTemplate->SetLicensingServiceParameters(params); } KeyGeneratorImpl generator(activationTemplate.get()); generator.SetKeyData("ExpirationDate", (int)0); generator.SetValidationData("LicenseKey", licenseKey.c_str()); generator.SetValidationData("HardwareId", hardwareId.c_str()); if (!licenseKeyValidationData.empty()) { generator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), licenseKeyValidationDataLen * 8); } try { activationKey = generator.GenerateKey(); } catch (LicensingException * ex) { if ((ex->GetCode() == STATUS_NET_ERROR) && (generator.GetSigningServiceStatusCode() == 406)) { m_licenseValidationResult.SetPaymentRequired(true); ex->Destroy(); } else throw; } if (ValidateActivationKey(activationTemplate.get(), false)) { activationStatus = STATUS_SUCCESS; } else throw new LicensingException(STATUS_GENERIC_ERROR, "internal error - invalid returned activation key"); m_licenseValidationResult.m_license = std::make_unique(); m_licenseValidationResult.m_license->SetHardwareId(hardwareId.c_str()); m_licenseValidationResult.m_license->SetActivationKey(activationKey.c_str()); m_licenseValidationResult.m_license->SetLicenseKey(licenseKey.c_str()); m_licenseValidationResult.m_license->SetLicenseKeyValidationData(licenseKeyValidationData.data(), licenseKeyValidationDataLen); int status = generator.GetSigningServiceStatusCode(); if (status == 200 /* HTTP OK */) m_licenseValidationResult.m_license->SetLease(false); else if (status == 201 || status == 202) m_licenseValidationResult.m_license->SetLease(true); m_licenseValidationResult.SetLicenseValid(true); } void SetLicensingServiceUrl(const char * url) { licensingServiceUrl = url; } int GetLicenseActivationStatus() { return activationStatus; } void GetLicenseExpirationDate(int * year, int * month, int * day) { if (licenseExpirationTime.tm_year > 0) { *year = 1900 + licenseExpirationTime.tm_year; *month = 1 + licenseExpirationTime.tm_mon; *day = licenseExpirationTime.tm_mday; } else { *year = 0; *month = 0; *day = 0; } } const char * GetCurrentHardwareIdCallback() { if (parentUsesWideChar) { static string hwid = w2s(GetCurrentHardwareIdW(parentLicensingClient)); return hwid.c_str(); } else { return GetCurrentHardwareIdA(parentLicensingClient); } } bool MatchCurrentHardwareIdCallback(const char * hwid) { if (parentUsesWideChar) { return MatchCurrentHardwareIdW(parentLicensingClient, s2w(hwid).c_str()); } else return MatchCurrentHardwareIdA(parentLicensingClient, hwid); } static const char * GetCurrentHardwareId() { return KeyHelper::GetCurrentHardwareId(); } static bool MatchCurrentHardwareId(const char * hwid) { return KeyHelper::MatchCurrentHardwareId(hwid); } void SetTimeValidationMethod(int method) { timeValidationMethod = method; } private: void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr) { size_t pos = 0; while ((pos = str.find(oldStr, pos)) != std::string::npos) { str.replace(pos, oldStr.length(), newStr); pos += newStr.length(); } } private: const LicenseTemplateImpl* licenseTemplate; LicenseValidationResultImpl m_licenseValidationResult; struct tm licenseExpirationTime; string licenseKey; string activationKey; string hardwareId; string licensingServiceUrl; vector licenseKeyValidationData; int licenseKeyValidationDataLen; int activationStatus; string licenseTemplateId; void * parentLicensingClient; bool parentUsesWideChar; int timeValidationMethod; int m_licenseValidityDays; //const char * (*GetCurrentHardwareIdCallback)(void * callerContext); //bool (*MatchCurrentHardwareIdCallback)(void * callerContext, const char * hwid); };