License Manager OverviewThe License Manager is a Java-based license management library for use by any Java project to maintain intellectual property security. It might just be a perfect world if all code were Open Source, but in the real world some projects are proprietary and licensed. This secure Java library helps you maintain, generate, store, secure and authenticate licenses in any Java-based application, whether desktop-, applet- or web-based.
License Manager takes advantage of the platform-independent 2048-bit RSA public/private key security and AES/SHA-1 + Triple DES/MD5 encryption built into the Java framework to help generate and secure licenses. Licenses can contain any number of data, be stored and transmitted in any format you see fit, and delivered by any mechanism your needs demand.
What does a license look like?The License object in License Manager contains several fields that can be used for a variety of purposes, as well as a "features" field that makes the license pretty ubiquitous. Here are the hightlights:
productKey - This String field can hold a product key, serial number, serial code or any other String-representable data necessary for identifying this license.
holder - This String field can hold the holder's name, common name (cname), X500Principal identification, UUID, Mac address, hardware ID, or any other String-representable data necessary for identifying this license.
issuer - This String can hold the issuing organization's name, common name (cname), X500Principal identification, UUID, or any other String-representable data necessary for identifying this license.
subject - This String can hold the product name, ID, code or any other String-representable data necessary for identifying this license.
issueDate - This field holds the date the license is issued/created (in Java Unix Epoch format¹).
goodAfterDate - This field holds the date the license becomes active, after which it is valid for use (in Java Unix Epoch format¹). It may or may not correspond to the issue date. If the license is perpetual, it simply need not be set.
goodBeforeDate - This field holds the date the license expires, after which it is vo longer valid for use (in Java Unix Epoch format¹). If the license is perpetual, it simply need not be set.
numberOfLicenses - This field holds the maximum users, seats, machines, etc. allowed access to the license, if that's something your product needs. If not, simply don't set it.
features - This is a set of License.Feature objects (see API documentation) containing feature names and expiration dates (in Java Unix Epoch format¹), if your product is such that you have different features that can be licensed or unlicensed. Expiration dates are optional; if a feature never expires or expires with the License, the expiration date can be omitted. If you want to provide an existing customer with a free-trial of a new feature, for example, this per-feature expiration date empowers that.
How are licenses kept secure?Enormous attention has been paid to keeping the License Manager secure and difficult, if not impossible, to tamper with. Even closed-source security code is open to vulnerability; Open Source security code must be more stringent and more carefully reviewed, since even malicious users have access to the source code. Thankfully, the nature of Open Source development means that the community will let you know quickly if a flaw is found in security-related code.
The following features/steps help keep the License Manager secure (and, in some cases, fast):
- Licenses are serialized in Java binary serialization form, which is more difficult to read plainly and tamper with than plain-text transmission.
- Licenses are then signed with the privake key of the issuer, which prevents tampering with the license without detection. Keeping the private key protected and a secret is the responsibility of the issuer.
- Next, the serialized and signed licenses are encrypted to prevent any confidential information they contain from falling into the wrong hands. Since the password implementation is up to the issuer, two issuers using License Manager can't necessarily decrypt each others' issued licenses, and it's even possible to have two different holders' licenses be encrypted with different passwords.
- The license is delivered by whatever means you see fit, as it is transmittable in either binary or ASCII format. This delivery mechanism can be as vulnerable or secure as your needs demand.
- The license is decrypted by the client application using the provided password, then deserialized and verified against the signature using the issuer's public key. If the license has been tampered with, it will be detected here.
- The license is cached in-memory to improve performance and prevent repetitive decryption and signature verification. This cache time is controllable by the issuer.
- The license object's features field is an "immutable set" collecton, meaning that any attempt to change the contents of the features, or their expiration dates, will be detected and result in errors.
- A proprietary Java Security Manager (read about this) built into the License Manager starts itself on application startup. No configuration or policy files are necessary to enable this security manager; it just works. This security manager prevents reflection attacks on any net.nicholaswilliams.java.licensing classes. It will yield to existing security managers that are equally or more strict, to prevent conflicts. If for any reason License Manager cannot find or install a security manager capable of protecting its classes from reflection attacks, it will fail to start and issue an error indicating the problem. It will not verify any licenses without an installed security manager.
- License Manager makes no assumptions about how you want your license content validated. You can choose not to validate license content or, if you want, you can implement a validation interface to check as few or many pieces of license content as you want. So, you can validate with as little as just checking the expiration date, or as much as checking the product key, Mac address, product ID, number of seats, and etc.
¹ Java Unix Epoch format is the number of milliseconds since the Unix Epoch (midnight on January 1, 1970 UTC). The current time is retrieved from System.currentTimeMillis(), and the time of any date X is retrieved from Calendar.getTimeInMillis() for any Calendar of date X.