PLUSNative: Validating Time-Limited and Subscription Licenses

Validating time-limited licenses is simple in principle. To do this you can simply check to make sure the system's current date is not past the license file's EffectiveEndDate. However, the tricky part is checking to make sure your application can trust the licensed system is reporting a reasonably accurate date. PLUSNative offers a variety of ways to validate the system's date, and it is up to you to pick and chose the methods most appropriate and reliable for your application based upon its needs and the expectations of the environments in which the application will run. If your licensing requirements never impose any time limits, then you may not need to worry about validating the licensed system's clock (although it would still be good to read through and understand the subject for future reference).

Date and Time Limitations

Important

Any software using 32 bit time_t values, including 32 bit Linux and macOS applications and libraries, may fail when using dates later than January 18, 2038, or dates earlier than December 13, 1901.

With versions 8.0 (Visual Studio 2005) and later of Microsoft Visual C++ compilers, 32 bit Windows applications use 64 bit time_t values. If your software is compiled using a different or older compiler or C runtime library, then your 32 bit software may be subject to the limitations noted above.

PLUSNative leverages common APIs that exist in standard C libraries for date parsing and manipulation. These functions use a time_t data type, which typically represents the number of seconds that have passed since January 1, 1970. The maximum date allowed varies on a number of factors, including the operating system targeted, the compiler used when compiling your application, etc... Refer to your compiler and/or development framework documentation for specifics on what limitations apply to your software.

Local Validation

Local validations are validations or checks your application can perform to prevent system clock tampering. PLUSNative offers a number of pieces of information and validation objects that you can use.

API Tampering

Regardless of what programming languages and/or frameworks are used to write your application, your application will ultimately end up making calls to operating system API functions to get the system's date and time. There are some tools available (such as "Time Stopper" or "RunAsDate") on the Internet, which essentially take the place of these operating system API functions in your application (via function hooking) and send an altered date to your application.  Unfortunately, this type of hack is very impractical to prevent without being very invasive. However, the good news is that detecting this type of hack is very easy, as these types of tools generally result in the underlying APIs always returning the same time. The example below shows how you can detect this kind of behavior in your application.

C/C++
if (SK_ERROR_NONE != SK_DateTimeValidateApi(SK_FLAGS_NONE, 0, 0, NULL))
{
/*TODO: The operating system's date and time APIs have probably been compromised. Your application should take appropriate action here.*/
}

Evaluating Date Properties

There are several properties stored in your application's license file that you can evaluate to prevent system clock tampering. These properties include:

To evaluate these dates, you could first create a small helper function that performs the necessary date arithmetic as shown below.

C/C++
BOOL IsDatePast(SK_XmlDoc license, const char *xpath, BOOL orPresent)
{
SK_ResultCode result = SK_ERROR_NONE;
char *value = NULL;
int remaining = 0;
BOOL past = FALSE;

do
{
result = SK_XmlNodeGetValueDateTimeString(SK_FLAGS_NONE, license, xpath, &value);
if (SK_ERROR_NONE != result)
{
/*TODO: Add error-handling code.*/
break;
}

result = SK_DateTimeDaysRemaining(SK_FLAGS_NONE, value, &remaining);
if (SK_ERROR_NONE != result)
{
/*TODO: Add error handling code.*/
break;
}

if (TRUE == orPresent && 0 == remaining)
{
past = TRUE;
break;
}

if (remaining < 0)
{
past = TRUE;
}
} while (FALSE);

SK_StringDispose(SK_FLAGS_NONE, &value);
return past;
}

While validating your application's license file, your application could then leverage the helper function to validate the date properties of the license file as shown in the code excerpt below.

C/C++
/*NOTE: This code assumes the "license" variable has been initialized using the SK_PLUS_LicenseGetXmlDocument function.*/

/*IMPORTANT: Licenses that never expire should not validate EffectiveEndDate.*/
if (TRUE == IsDatePast(license, "/SoftwareKey/PrivateData/License/EffectiveEndDate", FALSE))
{
/*The time-limited license has expired.*/
}

if (FALSE == IsDatePast(license, "/SoftwareKey/PrivateData/License/EffectiveStartDate", TRUE))
{
/*The license is not effective yet. Since this date usually represents the date in which the license was added in SOLO Server, this could indicate that the system clock has been back-dated.*/
}

if (FALSE == IsDatePast(license, "/SoftwareKey/PrivateData/License/SignatureDate", TRUE))
{
/*The system clock's date is earlier than the date SOLO Server signed the license file. This suggests the system clock has been back-dated.*/
}

/*IMPORTANT: Only validate LastUpdated when using writable license files, as this date is not present in read-only license files.*/
if (FALSE == IsDatePast(license, "/SoftwareKey/PrivateData/License/LastUpdated", TRUE))
{
/*The system clock's date is earlier than the LastUpdated date last saved in your application's writable license file. This suggests the system clock has been back-dated since the last time your application wrote to the license file.*/
}

Internet Validation

When possible, using an Internet source to validate a system's clock is a good way to determine whether or not the system clock is reporting a reasonably accurate time.

SOLO Server Web Services

When your application submits requests to SOLO Server's web services (including XmlActivationService, XmlLicenseFileService, and XmlNetworkFloatingService), SOLO Server checks the requesting system's date and time. SOLO Server is configured to require the requesting system's date and time to be within 24 hours of the server's date and time.  If you self-host SOLO Server or use SOLO Server Dedicated URL, you have the option to contact us to obtain additional information on adjusting this requirement. Whenever the requesting system is outside of SOLO Server's requirement, the web service response will reflect an error with a result code of 5022.

C/C++
result = SK_CallXmlWebService(context, SK_FLAGS_NONE, SK_CONST_WEBSERVICE_ACTIVATEINSTALLATION_URL, request, &response, &resultCode, &statusCode);
if (SK_ERROR_WEBSERVICE_RETURNED_FAILURE == result && 5022 == resultCode)
{
//Add logic to handle the SOLO Server time validation error here.
}

The small excerpt of code above shows how to detect when SOLO Server time validation errors occur when calling applicable web services from PLUSNative.

Automatic Recurring Payments

SOLO Server's Payment Plans allow you to offer subscription licenses, maintenance and support subscriptions, payment over multiple installments, and more. Learn more about how to configure SOLO Server for Payment Plans.