Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Programmer's Toolchest - Electronic Software Distribution


Sep00: Programmer's Toolchest

Licensing is the key

Jeremy and Sheridan work for Aladdin Knowledge Systems. They can be contacted at [email protected] and sheridana@ eAladdin.com, respectively.


Electronic software distribution (ESD) via the Internet is an attractive alternative to conventional delivery on CD-ROMs and diskettes, with the resulting efficiencies and savings in materials, production, and warehousing costs. In many instances, licensing is the main stumbling block to using the Internet as an electronic sales and distribution channel. Licensing is the specification of agreed terms between the owner of the intellectual property -- the software developer or publisher -- and end user who purchases the rights of use. Traditionally, this has been accomplished by paper licenses. However, it is becoming increasingly popular to translate the terms of use into certificates that can be distributed electronically and that place the primary burden of enforcement on the licensed application itself.

Use of electronic license distribution (ELD) offers a range of benefits to software vendors and end users alike. This includes the possibility of distributing an application once, then relicensing its features over time to accommodate changing customer needs.

For developers, integrating licensing into an application involves a variety of tasks that are tangential to the application itself. Although it is reasonable to implement a simple unlocking mechanism for, say, a single-license accounting application, it is much more complicated to provide a flexible and secure licensing system that lets vendors offer differential licensing of product components and network configurations. Luckily, there are commercially available ELD tools that provide the features, level of security, and robustness required to sell and distribute software. Aladdin (http:// www.eAladdin.com/), the company we work for, is one company that offers integrated licensing solutions. Other vendors in the integrated licensing market include Preview Systems (http://www .previewsystems.com/), Globetrotter Software (http://www.globetrotter.com/), and Rainbow Technologies (http://www .rainbow.com/).

Integrated Electronic Licensing

An integrated electronic licensing (IEL) system integrates general enforcement policy into the application itself, making a valid license a requirement for the application to run normally. Integration is generally implemented by the developer in one of two ways:

  • Through a licensing API, whereby function calls are placed strategically throughout the application's source code to create the enforcement policy.
  • Using enveloping or wrapping technologies that insert the enforcement policy into the application object code (executables or DLLs).

In either case, the system essentially alters the original application, transforming it into an application that is dependent on the existence of a valid license prior to execution.

A licensing API offers you a high degree of flexibility. You can protect a module of your application and determine how it should be used under different conditions. Furthermore, you can use API function calls to intermittently verify the communication sessions between your application and the licensing system. Finally, you can provide a single set of binaries that can be licensed, based on differential models, to better meet end users' needs.

Generally, licensing APIs include a minimal set of calls that must be implemented in a particular sequence. So, for example, you would probably initialize the interface, login to the application or feature to check license validity, and then logout prior to exiting the application; see Listing One. But the real value of using a licensing API lies in more structured use. For example, multiple login-logout sequences, strategically placed, can be used to effectively break up an application into licensable components, thus allowing components or features to be sold on a per-use basis; see Listing Two. End users can then purchase frequently used features, for example, and rent other features or components as the need arises.

Beyond the minimal set of functions, many licensing system APIs also provide additional functions that enable you to enhance and extend the licensing and sales models. For example, Aladdin's Privilege toolset includes the functions in Table 1 as part of its Client API. Listing Three shows the use of the PLC_ConsumeUnits function.

While lacking the flexibility of an API, wrapping enhances the security of the licensing solution. When well designed and implemented, the wrapping technology can incorporate active detection of debugging attempts, along with sophisticated encoding techniques to prevent hackers from disabling enforcement through reverse engineering. Producing this level of wrapping technology requires a high degree of development expertise, making it impractical for most in-house development teams.

In practice, it is best to employ a licensing API in conjunction with wrapping whenever possible. You would use the API calls to structure the licensing policy (components, usage consumption, and so on) within the application source code, then wrap the application to ensure the integrity of the overall licensing system by keeping the licensing policy hidden from prying eyes.

IEL Authentication Architecture

In implementing its Privilege IEL system, Aladdin chose a client/server architecture to provide reliable authentication of license terms under a variety of configurations, including single-CPU and concurrent network use.

Figure 1 illustrates the general data flow among the various Privilege components that interact with secure applications at the end-user's site. In effect, the secured application becomes the client. The application, in turn, looks to the server for authentication in determining whether license terms are met prior to, and during, execution.

For authentication purposes, you possess a unique key that must be provided to the server. The server then locates the licenses that have been requested by your application and, using the key, verifies that they are from an authentic source and that they have not been modified in any way.

So what are the advantages of this architecture? First of all, it separates the authentication from the licensed application itself. This means that licensing terms can be changed (for example, when end users purchase an additional term of use, concurrent seats, or new application components). Secondly, the Privilege Server runs within the end user's environment and is, therefore, highly available under the end user's control -- on a single machine, networked machine, or corporate server. Finally, access to the server provides a degree of asset management, because information about licenses is available and their use can be controlled within the organization.

License Characteristics

The goal of an electronic license is to translate traditional licensing terms into a form that can be transmitted electronically and thus used to implement ELD. While electronic distribution by definition includes phone and fax, increasingly ELD means that licenses are delivered to the end user via the Internet. Security is the paramount issue here. On the one hand, end users must be able to read the license and see its terms. (Organizations must be able to verify and manage the assets and services they purchase.) However, you want to ensure that, once the license is delivered, the purchased terms of use cannot be modified. In implementing Privilege, for example, Aladdin chose a simple text-file format (see Example 1). License content can be viewed using any standard text editor. Securing the license content is achieved by signing the license based on its content, and one of the authentication checks carried out by the Privilege Server is to verify, by means of the signature, that the license has not been tampered with. In addition, every license has a unique identity number, guaranteeing that no two licenses are identical.

License content specifies the terms of use that the developer wants to grant and should be flexible enough to support a variety of sales and distribution models including trial demos, rentals, component licensing, volume licensing, and so forth. Licensing terms that are a must are as follows:

  • Period of use. The term can start either when the software is installed or upon first execution, and continues for a specified period of time.
  • Usage based (metering). Usage may be measured by a counter that logs days of use, number of executions, or any other usage factor that can be measured.

  • Concurrency. For volume licensing deals, you want to be able to specify the number of concurrent users or sessions allowed.

Ideally, you should be able to mix terms to come up with the right configuration for each customer.

Another feature of the license is locking. How do you want to restrict the use of the software? You may want to lock a license (and thereby use of the application) to a specific machine. This can be accomplished by linking execution to an identifiable feature of that machine, such as a network interface card, hard disk drive, or processor's serial number, if available. For additional protection and portability, you can lock to a hardware security device. In some cases, you may not want to restrict copying of the licensed application at all. This is normally the case with trial demos, which you want to be distributed as widely as possible.

Secure Electronic Software and License Distribution

Once security and licensing issues have been resolved, you are able to get down to the business of distribution. While electronic licensing doesn't mean that you need a fully automated, web-based system, you'll probably want to integrate at least some aspects in addition to your traditional distribution system. You can use an automation control environment such as VBscript, Visual Basic, or ASP scripts to deliver software content. Privilege takes the automation process a step further by providing agents, including ActiveX controls or plug-ins and its LGCom object. The LGCom object is a (web) server-side component that interfaces with the license generation API to create and deliver licenses over the Internet. Terms of use can be either predefined in ASP script (see Listing Four) or presented as options in a form to be filled in by users.

Conclusions

Electronic software distribution and electronic license distribution hold the promise of new distribution channels, revenue models, and potential savings on inventory. But taking advantage of the Internet as an electronic sales and distribution channel means that you have to deal with numerous issues, especially those dealing with security, that simply go beyond what can be expected of an in-house solution. An integrated electronic licensing system that can be easily implemented is probably the ideal basis for most solutions. In choosing an IEL system, the key elements you want to look for are the level of security offered and a high degree of flexibility, which will allow you to offer your end users a variety of sales models and configurations to meet their changing needs.

Don't overlook the licensing API when evaluating licensing systems. This is the basis of a truly robust solution that allows you to distribute once and relicense as needs change. The ideal API should provide you with a wide degree of latitude in your implementation with a minimum of coding. By the same token, you should plan on using some form of wrapping to protect your licensing policy.

Finally, the licensing itself is of critical importance. Being electronically deliverable is not enough. It has to be secure, so you are certain that your customers are paying for the features they use. What's more, you want to make sure that the licensing solution you implement today will be able to support emerging sales models such as rental, component, and volume licensing.

DDJ

Listing One

#include "PLClient.h"           //Supplied by Privilege DK
#include "DevConst.h"           //Supplied by Privilege Developer SK
int     LoadApplication() 
{
        /*  Load Application 
            ...
        */
        return (0) ;
}
int main(int argc, char* argv[])
{
        PL_APIERR               Err ;
        PL_API_HANDLE           DevHandle ;
        PL_API_SESSION_ID       SessionId ;
        int                     AppExitCode ;

// Initialize the Privilege Client API
/* _PL_DEVELOPER_ID is an input parameter. It is your unique developer ID 
  declared in your  DevConst.h file.  _PL_DEV_COMM_PUBLIC_KEY is an input 
  parameter. It is your unique developer key declared in your DevConst.h file.
  CM_Network is an input parameter. Enables the application to search for 
  the Privilege Server both in the stand-alone machine and in entire network.
  DevHandle is an output parameter. The developer context handle created.
*/
        Err = PLC_DeveloperInit(_PL_DEVELOPER_ID,_PL_DEV_COMM_PUBLIC_KEY,
              CM_Network,&DevHandle);
/* Error, failed to initialize licensing API */
/* exit with an error code and do not load the application */
        if ( Err != PL_APIERR_OK )
                return (-1) ;   
/* Try to login to your license. Login operation will automatically search for
  a Privilege Server that can locate your license and log in to it.
  DevHandle is an input parameter. It is the developer context handle returned
  above. We define a feature name as an input parameter for which we will 
  request a login. SessionId is an output parameter. It is the session 
  ID for an instance of using the defined feature name.
*/
        Err = PLC_Login(DevHandle, "MyFeatureName", &SessionId);
/* Error, failed to login to the appropriate license, either it does not 
   exist or it is invalid for some reason. exit with an error code and 
   do not load the application */
        if ( Err != PL_APIERR_OK )
                return (-2) ; 
/* CONTINUE TO LOAD APPLICATION:
   If you got here, it means you have successfully logged into your license 
   and the license is valid.
*/  
        AppExitCode = LoadApplication() ;
/* APPLICATION EXITS: After your application terminates normally, execution 
   returns to this point. Just before it really exits you have some 
   small cleanup operations to do: 
*/
/* Close the established license session: */
Err = PLC_Logout( SessionId ) ;
/* Error, failed to close the license session. */
/* Just report the error when application exits */
        if ( Err != PL_APIERR_OK )
                return (-3) ; 
/* Uninitialize the Privilege Client API: */
/* The developer handle returned by previous call 
   to function PLC_DeveloperInit.*/
        Err = PLC_DeveloperUnInit( DevHandle ); 
/* Error, failed to uninitialize the Privilege Client API. */
/* Just report the error when application exits */
if ( Err != PL_APIERR_OK )
                return (-4) ; 
/* If you here, report the application exit code: */
        return (AppExitCode) ;
}

Back to Article

Listing Two

#include "PLClient.h"           //Supplied by Privilege DK
#include "DevConst.h"           //Supplied by Privilege Developer SK

/* Assume you want to protect three internal features of your application 
   with three different licenses based on three different licensing models.
   The three features are: Print, Save and NewDocument operations.
   Assume that your application calls one of the appropriate functions 
   described here when the user engages the feature. 
*/
/* DevHandle, is developer context handle returned upon initializing the API.  
   Declare this developer handle as a global variable.
*/
PL_API_HANDLE           DevHandle ;
int     LoadApplication() 
{
    /* Load Application */
    /* ... When needed call app_print/app_save/app_newdocument functions. */
        return (0) ;
}
int app_print( char* pFileNameToPrint , char* pDeviceName )
{
        PL_APIERR               Err ;
        PL_API_SESSION_ID       SessionId ;
        Err = PLC_Login(DevHandle,"Print",&SessionId);
 /* Error, failed to login to appropriate license, either it does not 
   exist or it is invalid for some reason. 
   Deny the print operation and exit function with an error code 
*/
        if ( Err != PL_APIERR_OK )
                return (-1) ;
        /************************************************/
        /*   Insert code for Printing here...
        /************************************************/
/* Close the established licesne session: */
        Err = PLC_Logout( SessionId ) ;                 
        if ( Err != PL_APIERR_OK )
                return (-2) ; 
        return (0) ;
}
int app_save( char* pFileNameToSave , char* pDeviceName )
{
        PL_APIERR               Err ;
        PL_API_SESSION_ID       SessionId ;
        Err = PLC_Login(DevHandle,"Save",&SessionId);
/* Error, failed to login to appropriate license, either it does not 
  exist or it is invalid for some reason. 
  Deny the save operation and exit function with an error code 
*/
        if ( Err != PL_APIERR_OK )
                return (-1) ; 
        /************************************************/
        /*   Insert Code here for the Save operation ...
        /************************************************/
/* Close the established license session. */
        Err = PLC_Logout( SessionId ) ;                 
        if ( Err != PL_APIERR_OK )
                return (-2) ; 
        return (0) ;
}
int app_new_document( char* pFileNameToSave , char* pDeviceName )
{
        PL_APIERR                        Err ;
        PL_API_SESSION_ID          SessionId ;
        Err = PLC_Login(DevHandle,"NewDocument",&SessionId);
/* Error, failed to login to appropiate license, it either does not exist or 
   is invalid for some reason. 
   Deny the new document operation and exit function with an error code.
*/
        if ( Err != PL_APIERR_OK )
                return (-1) ; 
        /************************************************/
        /*   Insert to do code for New document operation ...
        /************************************************/
        /* Close the established licesne session: */
        Err = PLC_Logout( SessionId ) ;                 
        if ( Err != PL_APIERR_OK )
                return (-2) ; 
        return (0) ;
}
int main(int argc, char* argv[])
{
        PL_APIERR       Err ;
        int             AppExitCode ;
/* In the main function just initialize/uninitialize the licensing API */ 
// Initialize the Privilege Client API
        Err = PLC_DeveloperInit(_PL_DEVELOPER_ID,_PL_DEV_COMM_PUBLIC_KEY,      
                                  CM_Network,&DevHandle);
        if ( Err != PL_APIERR_OK )
                return (-1) ;
        /* Insert code for Load operation ... */  
        AppExitCode = LoadApplication() ;
/* APPLICATION EXITS:
   After application terminates normally, execution returns to this point. 
   Just before it really exits you have some small cleanup operations to do: 
*/
/* Uninitialize the Privilege Client API: */
        Err = PLC_DeveloperUnInit( DevHandle ); 
        if ( Err != PL_APIERR_OK )
                return (-2) ; 
/* If you are here, report the application exit code: */
        return (AppExitCode) ;
}

Back to Article

Listing Three

#include "PLClient.h"           //Supplied by Privilege DK
#include "DevConst.h"           //Supplied by Privilege Developer SK

int func_print( int Resolution, char* FileToPrint )
{
        PL_APIERR               Err ;
        PL_API_HANDLE           DevHandle ;
        PL_API_SESSION_ID       SessionId ;
        int                     UnitsToConsume ;
// Initialize the Privilege Client API
/* _PL_DEVELOPER_ID is an input parameter. It is your unique developer 
      ID declared in your DevConst.h file. 
  _PL_DEV_COMM_PUBLIC_KEY is an input parameter. It is your unique developer 
     key declared in your DevConst.h file.
  CM_Network is an input parameter. Enables application to search for 
     Privilege Server both in stand-alone machine and entire network.   
  DevHandle is an output parameter. The developer context handle created.
*/
        Err = PLC_DeveloperInit(_PL_DEVELOPER_ID,_PL_DEV_COMM_PUBLIC_KEY, 
                                CM_Network, &DevHandle );
        if ( Err != PL_APIERR_OK )
                return -1 ;
// Try to perform login to name "Print" representing component to be licensed. 
/* DevHandle is an input parameter. It is developer context handle 
   returned above */ 
/* We define a feature name "Print" as an input parameter for which 
   we will request a login. */
/* SessionId is an output parameter. It is session ID for an 
   instance of using the defined feature name.*/
        Err = PLC_Login( DevHandle,"Print", &SessionId );
// Error, failed to login to appropriate license, either it does not 
// exist or it is invalid for some reason. 
        if ( Err != PL_APIERR_OK )
                return -2 ;
// Decide how many units to consume from the license
/* Each time user prints a document at a resolution of 300 dpi, 
   20 units must be deducted from counter, at 600 dpi 50 units must 
   be deducted and at the default resolution 40 units must be deducted.
*/
switch ( Resolution )
{
                case    300 :
                        UnitsToConsume = 20 ;
                break ;
                case    600 :
                        UnitsToConsume = 50 ;
break ;
               default :
                        UnitsToConsume = 40 ;
break ;
        } ;
/* The session ID is an input parameter, it is returned from previous call 
   to PLC_Login */
/* UnitsToConsume is an input parameter to number of units to be deducted 
   from the counter */
        Err = PLC_ConsumeUnits( SessionId,UnitsToConsume );
        if ( Err != PL_APIERR_OK )
                return -3 ; 
/* If you got here, it means license was checked and updated and you can 
  go on with printing, but first you have some small cleanup operations to do:
*/      
// Close the established license session.
/* The session ID is an input parameter, returned by previous call to 
   PLC_Login */
        Err = PLC_Logout( SessionId ) ; 
// Error, failed to close license session. 
        if ( Err != PL_APIERR_OK )
                return -4 ; 
// Uninitialize the Privilege Client API
/* DevHandle is an input parameter, it is the handle returned by 
   previous call to PLC_DeveloperInit */
        Err = PLC_DeveloperUnInit( DevHandle );
// Error, failed to uninitialize the Privilege Client API. 
        if ( Err != PL_APIERR_OK )
                return -4 ; 
// Insert your actual printing code...
}

Back to Article

Listing Four

<HTML>
<HEAD>
<TITLE>LGCom Sample</TITLE>
</HEAD>
<%
'
'   This sample shows how to use the Privilege License Generator COM object
'   (LGCom) from within an ASP page (VBScript) to create a simple license.
'       GenLicense():
'   A function that creates a simple license file.
'   License will be locked to a specific machine (strLockID), it will 
'   be identified by a specific feature name, it will have a descriptive 
'   license name and will be saved to a required file path (no license 
'   terms are specified). If the function is successful, it returns a new 
'   license ID and a license signature that allows regenerating the same 
'   license file again.
'       parameters:
'        strLicenseName - [in] license name
'        strFeatureName - [in] license's feature name
'        strLockID              - [in] locking ID (host ID)
'    strLicFilePath - [in] new license file path 
'        nLicID             - [out] license ID
'        strLicSignature- [out] license signature
'       return value:
'        either 0 (everything is OK) or an error code
function GenLicense( strLicenseName, _strFeatureName, _strLockID, 
         _strLicFilePath, _ByRef nLicID, _ByRef strLicSignature )
        on error resume next
        Err.Clear
        ' Create an instance of the LGCom object
        ' LGCom.dll must be registered on the server
        set LG = Server.CreateObject( "LGComAx.LGCom" )
        ' set LG properties for LoginToAccount
        LG.DevId = &hFFFFFFF1   ' demo developer ID (required)
        LG.sDevName = "DevName" ' developer name    (optional)
        ' login to the Privilege developer account 
        ' keys file of the developer must be installed on the machine
        nRet = LG.LoginToAccount()
        if Err.number <> 0 then
                GenLicense = Err.number
                exit function
        end if
        if nRet <> 0 then
                GenLicense = nRet
                exit function
        end if
        ' set LG properties for CreateLicense
        LG.sLicenseName     = strLicenseName ' license name (optional)
        LG.sFeatureName     = strFeatureName ' feature name (required)
        LG.sHostId          = strLockID      ' host id (optional)
    ' other license terms can be set here 
    ' for example: expiration date, units to consume, max concurrency, etc.
        LG.sLicenseFilePath = strLicFilePath ' output file path (required)
        ' create the license
        nRet = LG.CreateLicense()
        if Err.number <> 0 then
                GenLicense = Err.number
                LG.LogoutFromAccount()
                exit function
        end if
        if nRet <> 0 then
                GenLicense = nRet
                LG.LogoutFromAccount()
                exit function
        end if
        ' get output parameters to be returned
        nLicID          = LG.LicenseId ' created license ID
        strLicSignature = LG.Signature ' license signature  
        LG.LogoutFromAccount()
        set LG = nothing
        GenLicense = 0
end function
%>
<BODY>
<h2>Privilege LGCom Test</h2>
<%
   strLicenseName = "License Name"
   strFeatureName = "Test Feature"
   strHostId      = "013ae2ef5fc77588284f5f18"
   strOutputDir   = "C:\Temp\"     ' path should exist on the server
   strFileName    = "License1.plf"
%>
<b>Input Parameters</b>:<br>
License Name - <i><%= strLicenseName %></i><br>
Feature Name - <i><%= strFeatureName %></i><br>
Host Id -      <i><%= strHostId %></i><br>
Output Path -  <i><%= strOutputDir + strFileName %></i><br> 
<br>
<%   
   nRet = GenLicense( strLicenseName, _strFeatureName, _strHostId, 
               _strOutputDir + strFileName, _nLicenseId, _strSignature )
%>
<% if nRet = 0 then %>
<b>License created successfully</b><br>
License Id: <i><%= Hex( nLicenseId ) %></i><br>
<% else %>
<b>Can not create license</b><br>
Error: <i><%= Hex( nRet ) %></i><br>
<% end if %>
</BODY>
</HTML>

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.