PLUSNative: Manual Activation (Offline Method)

When Internet access is not available and online activation is not possible, manual activation is the recommend method for activating an installation and obtaining a license file from SOLO Server. This involves the end-user copying the activation request or saving it to a file that they would take to another computer with Internet access. They would then paste the request or upload the file to SOLO Server's manual request page, which processes the request and generates a response. The end-user must then copy this response or save it to a file and return to the computer they are attempting to activate. Finally, they must paste in the response or point the application to the file. The application can then parse the response and determine which action to take.

The following example demonstrates manually activating an installation, retrieving a license file from SOLO Server, and saving that license file to disk.

Generating and Encrypting the Request

The PLUSNative library has built-in functions for generating requests for the SOLO Server XML Activation Service and XML License File Service web services. Use of these functions avoids having to manually build the web service XML request document. If one finds it necessary, the XML request document can be modified using any of the XML helper functions. For instance, new elements can be added using the SK_XmlElementAddNew function. Once the request has been generated, it must be encrypted and digitally signed.

The following code snippet demonstrates generating the manual activation request:

//declare variables
SK_ResultCode result = SK_ERROR_NONE;
SK_ApiContext context = NULL;
SK_XmlDoc request = NULL;
SK_XmlDoc encryptedRequest = NULL;
char *encryptedRequestString = NULL;
int requestSize = 0;
SK_XmlDoc encryptedResponse = NULL;
SK_XmlDoc response = NULL;
int resultCode = 0;
char *originalSessionCode = NULL;
char *responseSessionCode = NULL;
SK_XmlDoc license = NULL;

//initialize API context (usually called during application start-up)
//refer to the Configuring the API Context topic for instructions

//generate the activation request
result = SK_SOLO_ActivateInstallationGetRequest(context, SK_FLAGS_NONE, 123, "password", NULL, 1000, 1000, FALSE, "My Installation", NULL, &request, &originalSessionCode);

//save the originalSessionCode for later validation

//encrypt/sign the request
result = SK_XmlDocumentEncryptRsa(context, SK_FLAGS_NONE, FALSE, &request, &encryptedRequest);

//get our request as a string
result = SK_XmlDocumentGetDocumentString(SK_FLAGS_NONE, encryptedRequest, &encryptedRequestString, &requestSize);

//free our encrypted request document
SK_XmlDocumentDispose(SK_FLAGS_NONE, &encryptedRequest);

//allow the user to copy the request string or save it to a file

The above request is generated using fictional hard-coded data for demonstration purposes. The code snippet above omits many of the parameters necessary to initialize the API context (the context variable). Refer to the Configuring the API Context topic for instructions and a complete example of calling the SK_ApiContextInitialize function.

Using the SOLO Server Manual Request Page

Once the user generates the manual activation request, they must take it to a computer with Internet access where they can paste it in or upload it to the SOLO Server manual request page. If SOLO Server is able to successfully process the manual request it will generate a response that must be taken back to the computer being activated. Otherwise, it will display an error message and it may be necessary for the end-user to contact support for help and possibly have to start the process over.


The above SOLO Server Manual Request link is for use with Instant SOLO Server only. If you are using a dedicated or externally-hosted SOLO Server, this will need to be updated to point to your specific domain.

Decrypting and Parsing the Response

After the end-user returns to the computer being activated with the encrypted response, it must be decrypted and verified. Once done, you must manually parse the response to determine what actions to take. Here, the XML helper functions are used here to extract the data out of the response document. A read-only license file is contained as a sub-document in the response's License node. Once you extract the license document from the response you can save it to disk.

//allow the user to paste the response string or load it from a file

//load the response string into an XML document
result = SK_XmlDocumentCreateFromString(SK_FLAGS_NONE, responseString, &encryptedResponse);

//decrypt/verify the response
result = SK_XmlDocumentDecryptRsa(context, SK_FLAGS_NONE, FALSE, encryptedResponse, &response);

//free our encrypted response document
SK_XmlDocumentDispose(SK_FLAGS_NONE, &encryptedResponse);

//get the SessionCode from the response
result = SK_XmlNodeGetValueString(SK_FLAGS_NONE, response, "//SessionCode", FALSE, &responseSessionCode);

//load our originalSessionCode that was previously saved

//verify the session codes match
if ((NULL != responseSessionCode) || (NULL == strstr(originalSessionCode, responseSessionCode)))
//handle error condition

//clear our originalSessionCode that was previously saved

//free our session code strings
SK_StringDispose(SK_FLAGS_NONE, &originalSessionCode);
SK_StringDispose(SK_FLAGS_NONE, &responseSessionCode);

//get the license sub-document
result = SK_XmlNodeGetDocument(SK_FLAGS_NONE, response, "/ActivateInstallationLicenseFile/PrivateData/License", &license);

//free our response document
SK_XmlDocumentDispose(SK_FLAGS_NONE, &response);

if (NULL != license)
//save the license file to disk
result = SK_PLUS_LicenseFileSave(context, SK_FLAGS_NONE, filename, license);

//free our license document
SK_XmlDocumentDispose(SK_FLAGS_NONE, &license);

Although the above example saves the license file to disk, it can actually be saved anywhere, such as in a database. In such a scenario, your application would only need to save the license string. If you don't save the license file using SK_PLUS_LicenseFileSave, it is necessary to call SK_PLUS_LicenseLoad to load the newly obtained license into memory.


If the user is pasting in a response instead of loading a response file, there are a few potential issues to be aware of:

These issues do not occur when the encryption response is loaded from a file.

Session Code Validation

This example uses session code validation to prevent the end-user from processing the same response multiple times, which is known as a replay attack. A random session code is generated and included in each web service request. This session code must be saved somewhere on the system so it can later be retrieved and compared to the session code found in the web service response. If the session codes match then you know the response was the response associated with the original web service request. Otherwise, the response should be consider invalid.


These basic source code examples omit important and necessary error checking for the sake of clarity. Many of the functions used could fail for one reason or another, and it is important that you make sure each function call succeeds before passing the result from one function to another. Otherwise, you may not be able to tell exactly where a problem originated if and when one occurs.