Click here to Skip to main content
Click here to Skip to main content

Using XML Digital Signatures for Application Licensing

By , 23 Nov 2005
 

Introduction

At some point in most developers' lives, application licensing becomes a problem. Many solutions exist but are often expensive and difficult to implement. Few offer seamless integration with an existing code base. In such a case, writing an in-house licensing mechanism may be desired. Such a task, however, is faced with many problems.

One of the biggest challenges of any licensing mechanism is to create a scheme that can't be hacked by the user. Some schemes rely on the Internet to provide an authentication system. Obviously, such a scheme requires an Internet connection which can be a burden on the user. Putting information on the user's computer, however, also gives the user an opportunity to hack the licensing scheme. What's needed is a solution that can reside on a user's computer but one that can't be changed.

Such a solution does exist: XML Digital Signatures. Actually, public-key cryptography in general can solve the problem, but the ease and flexibility of both XML[1] and XML Digital Signatures[2] make using XML Digital Signatures an attractive solution.

This article will explain the basic premise public-key cryptography and how it relates to XML Digital Signatures, detail the creation of a key pair, give examples for signing and verifying an XML document, and discuss different implementations to provide reliable application licensing.

Note: this is not a full solution that you can simply add to your application, but a tutorial about how to sign XML using XML Digital Signatures. I offer a simple implementation only as an example. There are many third-party libraries that use similar techniques that are ready for integration into your product(s) and ready for deployment.

Cryptography

To put it simply, cryptography is merely the means of hiding text. Plain text is run through algorithms of varying complexity to produce cipher text, or unreadable text[4]. Converting plain text to cipher text is known as encryption, and converted cipher text back to plain text is known as decryption. While many developers may be inundated with the details, this doesn't have to be a complex process. Cryptography has been around circa 1900 BC. At first, cryptography was nothing more than "non-standard" glyphs. Even relatively modern cryptographic algorithms aren't always complex. ROT13 was - and perhaps still is - used in USENET to hide plain text from indexers by shifting alphabetical characters 13 spaces. So, an "A" becomes an "N", a "B" becomes an "O", and so on.

Admittedly, many modern cryptographic algorithms are complex, but you most often only need to know the basics to implement and use cryptography in your applications. The simplest form of cryptography uses symmetrical algorithms. This means that two or more parties share the same key (or passphrase) that is used to encrypt and decrypt information. ROT13, which was mentioned early, is just one of many examples of symmetrical keys, where the key is simply the rule that characters should be shifted by 13 spaces. Most modern cryptographic algorithms use asymmetrical algorithms, when each party has both a private key and a public key. This is also known as public-key cryptography. The most popular algorithm is RSA[5] and examples can be found in SSL, PGP, S/MIME, and many other secure standards.

With asymmetrical algorithms, a private and public key - known as a key pair - are generated by a user using private or random data. The private key is kept secret and secure, but the public key is given freely. The sender will use the recipient's public key to encrypt information, while the recipient will use their private key to decrypt the information. Information can also be signed in a similar fashion, except that the sender will use their private key to encrypt a hash of the plain or cipher text, and the recipient will use the sender's public key to decrypt and verify the hash. If the information was changed in any way, the hash will be invalid and the signature verification will fail. Using this technology with XML produces the XML Digital Signatures that we will use to license applications.

XML Digital Signatures

XML Digital Signatures, using public-key cryptography which was discussed earlier in this article, solves the problem of verifying that information came from a particular source, and that the information has not changed. This standard is just one of many included in Microsoft's WS-Security Specification[6] and can be used to verify the source of a Web Service response, or to verify that any XML data has not changed since it was signed.

Signatures are created by linking references to several transformations together over the content of the XML document, either in whole or in part. One of these transformations is a hash - a one-way checksum that is unique to the source content; even changing a single character will result in an entirely different hash. The most popular hash algorithms are MD5[7] and SHA1[8]. Because XML documents can have different indentation and amounts of white space, typically a canonicalization method is applied. A canonicalization method removes white space and other formatting, thereby reducing XML data to its simplest form. This is important because generating a hash over XML documents with the same data but different formats will result in two different hashes. Finally, a signature transformation is applied to encrypt the hash.

The XML Digital Signature - a composite of the things mentioned earlier, and usually containing the public key that signed it - can take on different forms in relation to the XML document which was signed. An enveloped signature is contained under the document element of the XML document which was signed, while an enveloping signature contains the XML document within the signature. Signatures can also be detached. Because an enveloped schema preserves the original XML schema[9] with only a reference to the qualified Signature element in the "http://www.w3.org/2000/09/xmldsig#" namespace:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="license"
  targetNamespace="http://www.codeproject.com/dotnet/xmldsiglic.asp"
  elementFormDefault="qualified"
  xmlns="http://www.codeproject.com/dotnet/xmldsiglic.asp"
  xmlns:mstns="http://www.codeproject.com/dotnet/xmldsiglic.asp"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"
  version="1.0">
  <xs:import id="schema" namespace="http://www.w3.org/2000/09/xmldsig#"
  schemaLocation="xmldsig-core-schema.xsd" />
  <xs:element name="license">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="computerName" type="xs:string"
          minoccurs="1" maxoccurs="1" nillable="false" />
        <xs:element name="expires" type="xs:dateTime"
          minOccurs="1" maxOccurs="1" nillable="false" />
        <xs:element ref="dsig:Signature"
          minOccurs="0" maxOccurs="1" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Because the dsig:Signature element is optional, this schema applies to both signed and unsigned licenses. It also allows applications to parse the license document without validating the signature or extracting content from an otherwise different schema (such as in the case of an enveloping schema). I prefer this type of signature and will use it in the examples provided later in this article, and in the sample source code.

The Code

The following code will demonstrate creating key pairs, and signing and verifying XML content. The principles presented can be applied to many solutions that require - or that would benefit from - XML Digital Signatures. While the sample source does sign a license request file and verify a signed license against a specific public key, the specifics of this solution as it applies to licenses are explained later.

Key Creation

Key creation is a straight-forward process of creating a public and private key, or a key pair. While many utilities exist to create a key pair, the sn.exe[10] utility provided in the Microsoft .NET Framework SDK will be used. This utility allows you perform many tasks related to strong-named assemblies, including generating key pairs and saving them to a binary file.

First, the key pair is created from the command line:

sn.exe -k KeyFile.snk

In the sample source, the same key pair is used for license request signing and for signing strong-named assemblies. In production environments, you may want to have separate keys to prevent a cracked key from being used to sign modified assemblies or to sign falsified license requests.

Because the public key shouldn't be added to the signature output - which will be discussed later - it should be obtainable from the verification code. The .NET classes can easily create a crypto key from an XML fragment that represents a public key, so the public key will be embedded as a resource into the sample Verify.exe utility. To allow for this step and to make signing easier, the public key shall be imported into a key container on your machine:

sn.exe -m y
sn.exe -i KeyFile.snk CodeProject

The first command merely tells following container commands to act on a container for the machine instead of the user. Specify 'n' to have commands enacted on user containers. The second command installs the key pair into a key container named 'CodeProject' which provide easy access to the key container from a variety of crypto utilities. The sample Sign.exe signature utility can easily access this key container - much more easily than reading an XML document and importing the inner XML of the document element. While that and many other ideas are viable options for such a solution, the use of key containers in all but signature verification will be used throughout this article and sample source.

Finally, the public key must be extracted from the key pair and exported to an XML document. Because the key pair is now in a key container, this code is made simple:

CspParameters parms = new CspParameters(1);
parms.Flags = CspProviderFlags.UseMachineKeyStore;
parms.KeyContainerName = "CodeProject";
parms.KeyNumber = 2;
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(parms);
Console.WriteLine(csp.ToXmlString(false));

Thanks go out to Pol Degryse for pointing out that I must explicitly set which store to use despite to what sn.exe set the default store, and to Michel Gallant, Security MVP, on microsoft.public.dotnet.security for pointing out that each container uses two key pairs, and that I must specify AT_SIGNATURE (2) instead of the default AT_KEYEXCHANGE (1), which caused the key pair to be unique on different machines.

Since this code writes the XML fragment to standard out, simply redirect standard out to a file that will be embedded into the Verify.exe project:

ExtractPubKey.exe > PubKey.xml

Add the file PubKey.xml as an embedded resource into the Verify project for later use.

Signing

To sign the XML document with an enveloped XML Digital Signature, we'll need to take into account various factors. Because the content to be signed contains the signature that contains the hash of the content, we obviously can't sign the entire content because the signature isn't computed until the hash is computed. We must also ensure that white space is ignored when computing the signature otherwise even a change in white space due to various transport issues could render the signed document invalid.

Transform algorithms[11] solve these and many other problems by applying specific algorithms to the original content or to output from other transforms. One particular transform eliminates white space and optionally comments in the computation of the signature: Canonicalization[12]. Canonicalization uses the character set to determine which characters shouldn't be included in the signature computation. Optionally, comments can be removed from the computed signature depending on which canonicalization method is used.

Another transform algorithm of interest is the Enveloped Signature Transform[13]. This transform uses XPath expression "not(ancestor-or-self::dsig:Signature)" to filter the signature during computation. The end result is that only the content is signed with or verified against the hash. The signature - which would change when the hash changes - is not included in the hash.

Once the necessary transforms have been chosen, they are applied to the content to sign:

// Load the license request file.
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(args[0]);

// Get the key pair from the key store.
CspParameters parms = new CspParameters(1);
parms.Flags = CspProviderFlags.UseMachineKeyStore;
parms.KeyContainerName = "CodeProject";
parms.KeyNumber = 2;
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(parms);

// Creating the XML signing object.
SignedXml sxml = new SignedXml(xmldoc);
sxml.SigningKey = csp;

// Set the canonicalization method for the document.
sxml.SignedInfo.CanonicalizationMethod = 
  SignedXml.XmlDsigCanonicalizationUrl; // No comments.

// Create an empty reference (not enveloped) for the XPath
// transformation.
Reference r = new Reference("");

// Create the XPath transform and add it to the reference list.
r.AddTransform(new XmlDsigEnvelopedSignatureTransform(false));

// Add the reference to the SignedXml object.
sxml.AddReference(r);

// Compute the signature.
sxml.ComputeSignature();

// Get the signature XML and add it to the document element.
XmlElement sig = sxml.GetXml();
xmldoc.DocumentElement.AppendChild(sig);

// Write-out formatted signed XML to console (allow for redirection).
XmlTextWriter writer = new XmlTextWriter(Console.Out);
writer.Formatting = Formatting.Indented;

try
{
  xmldoc.WriteTo(writer);
}
finally
{
  writer.Flush();
  writer.Close();
}

In the code, the public key of signing key pair is not included in the output for reasons that will be covered in better detail in the Licensing topic.

Verifying

To verify the signed XML document, we simply load the signed XML document, reconstitute the cryptographic service provider (CSP) from the embedded XML public key resource, and verify the Signature node in the signed XML document against the public key in the CSP. The SignedXml object that we used to sign the XML will automatically determine which standard transforms were applied and will compute and verify the hash based on the transforms used when the document was signed:

// Get the XML content from the embedded XML public key.
Stream s = null;
string xmlkey = string.Empty;
try
{
  s = typeof(Verify).Assembly.GetManifestResourceStream(
    "CodeProject.XmlDSigLic.PubKey.xml");

  // Read-in the XML content.
  StreamReader reader = new StreamReader(s);
  xmlkey = reader.ReadToEnd();
  reader.Close();
}
catch (Exception e)
{
  Console.Error.WriteLine("Error: could not import public key: {0}",
    e.Message);
  return 1;
}

// Create an RSA crypto service provider from the embedded
// XML document resource (the public key).
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(xmlkey);

// Load the signed XML license file.
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(args[0]);

// Create the signed XML object.
SignedXml sxml = new SignedXml(xmldoc);

try
{
  // Get the XML Signature node and load it into the signed XML object.
  XmlNode dsig = xmldoc.GetElementsByTagName("Signature",
    SignedXml.XmlDsigNamespaceUrl)[0];
  sxml.LoadXml((XmlElement)dsig);
}
catch
{
  Console.Error.WriteLine("Error: no signature found.");
  return 1;
}

// Verify the signature.
if (sxml.CheckSignature(csp))
  Console.WriteLine("SUCCESS: Signature valid.");
else
  Console.WriteLine("FAILED: Signature invalid.");

Licensing

Using the described concepts for application licensing covers the technical aspects of protecting your licensed code while providing the user a simple licensing mechanism that can be Web- or email-based merely to obtain the license. These concepts alone, however, are not enough to provide an effective licensing toolset. There are a number of things you must consider when designing your application licensing model. Some concepts discussed here are implemented and are simplified to give you a simple example.

One thing you must consider is that license files can be transferred from one computer to another. If a single individual were to purchase a license and license had no unique identifier tied to the individual's machine or personal identity, he or she could easily post or resell the license.

To combat this problem, you should include some unique identifier in the license file. If you want to limit the license to a single machine, you could include the MAC address or computer SID in the license and - after verifying the signature - compare the stored unique identifier with that of the computer. While the signed XML document may be valid, two different identifiers would render the license invalid. There are a number of things you can use to identify the machine, but you should make sure that the identifier would be unique from computer to computer.

You could - depending on your license model - also use a unique personal identifier but it must be automatically obtained. If you ask the user or query an application for information that could be changed without affecting a user's environment - such as an email address from Outlook without authentication - the user could easily lie. One example would be to use the user's Microsoft Passport PID. Because the user is forced to authenticate in order to obtain this information, the user identity could be trusted within reason depending on your policy.

For this example, I simply get the computer name from the Environment class. In practice, I have written a Managed C++ assembly which grabs the computer SID which is unique to every computer in a given domain.

You should also consider implementing an expiration date or a combination of a signing date and certain number of days after that date before the signature is invalidated. This practice is common in cryptography systems and provides a means of discontinuing products and services to license violators or clients who no longer exist and who might sell their equipment whole-sale. You could even provide a revocation list (a list of forcibly-expired licenses) - which can be found in SSL[14] implementations - but that would force a dependency on the Internet in order to periodically check the revocation list.

Last in this topic - but certainly not the final consideration - is that the client code should not containing any private key information and should not allow for identity or key spoofing.

In the code earlier, the XML public key file was embedded into the verification application. It just as easily could have been encoded directly into the source code. Because the code contains this public key, it can verify the signature against that key instead of using a public key in the XML Signature element. If the verification code were to trust the public key in the signed document, then anyone could sign a new license with their private key, and their public key would be included and used to verify the document.

Embedding the private key (or the entire key pair) would be, perhaps, even worse because they could not only sign a new license with your private key, but they could extract the key pair and use it to sign assemblies that look like your or your organization's assemblies. They could easily decompile, change, and recompile and sign your assemblies while maintaining their validity, while effectively replacing your code with possible malicious code and could distribute it to clients. The assembly is signed, after all, with your key pair.

Even keeping your private key secure - another good argument for key containers over key pair files - this mechanism can be circumvented. Because .NET assemblies can be decompiled even with tools like ildasm.exe[15] in the Microsoft .NET Framework SDK, changed, and recompiled with a new signing key, you should take great care of obfuscating your code, burying the verification assembly deep in a chain of assemblies that automatically verify dependent assemblies based on their strong names while the CLR verifies each assembly's hash, and maintaining your hold on your code. No cryptography system is perfect, but you can take measures to make it fool-proof; that is, protected from "fools" who don't know any better.

How is this information obtained?

This information can be obtained through a request process. This is common in some cryptographic systems like SSL where an individual requests that a license be signed with information the individual has assigned. In our example, a separate client application - such as a small Windows or command-line utility, or even an ActiveX control or Java applet on a Web site - or even a trial version of your application, would gather information about the user that is unique to their machine or identity. The user or the applet would then send that request to you or your organization to be signed and returned to the user. In this way, you get the information that is required to validate the identity of the client machine or personal identity while controlling the private information and, thus, the ability to sign the request. If you implemented an expiration date or the user changes pertinent information, they would have to resubmit their request with the updated data for you to sign - if you or your organization wishes to renew the license. This gives you ultimate control over your licensed application and can be as flexible as you design it.

To continue our example, let's take our simple license schema and view an example request file generate on the client's machine:

<license>
  <computerName>MYCOMPUTER</computerName>
  <expires>2003-09-31T00:00:00</expires>
</license>

The request file contains the computer name (remember that this is only an example and a computer name would not be guaranteed to be unique and could easily be changed) and an expiration date. The user would then send the license request file or fragment to you or your organization. After reviewing and, possibly, generating a purchase order, you would run the signing application on the request file and send it back to the user through an automated manner, or with instructions for installing the file on their machine.

If the above request was passed to the sample Sign.exe application, the following output would be generated:

<license>
  <computerName>MYCOMPUTER</computerName>
  <expires>2003-09-31T00:00:00</expires>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod
        Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod
        Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
      <Reference URI="">
        <Transforms>
          <Transform
          Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>eU3Par59M28X1c1DNORnhmW0Z2Y=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>epyuHLJbmyscoVMg2pZZAtZJbBHsZFUCwE4Udv+u3TfiAms2HpLgN3cL
      NtRlxyQpvWt1FKAB/SCk1jr0IaeE7oEjCp2mDOOHhTUTyiv2vMJgCRecC1PLcrmR9ABhqk
      itsjzrCt7V3eF5SpObdUFqcj+n9gjuFnPQtlQeWcvKEcg=</SignatureValue>
  </Signature>
</license>

Note: The SignatureValue value has been wrapped for your convenience but should be a on a single line.

If you pass the signed document through the Verify.exe application, you will see that the signature is valid and that the document was not changed. If you change any content within the document - such as the expiration date or computer name - and run the verification application again, the signature will be invalid since the encrypted hash value is different from the computed hash over the changed content. Add to that checks against the computer name, expiration date, and even whether or not the file exists, and you will have effective license validation.

Summary

XML Digital Signatures use industry-standard encryption to sign XML documents. Using XML documents for license request files allows you to control what your clients can do with your application and for how long they may do it, and allows you to provide a disconnected license mechanism that is both secure and unique to a particular machine or user. The APIs that provide this level of functionality already exist in the Microsoft .NET Framework base class library and are easy to use and provide the same object-oriented programming model as the rest of your .NET applications.

Licensing your application doesn't have to be difficult. With XML Digital Signatures and well-designed validation, you can have a simple yet effective licensing mechanism that is both extensible and that uses industry standards.

References

Below you will find a list of reference that were either used during the writing of this document, or that you may find helpful in gaining a better understand of the topics to which these references apply. Other references used over the years for general research into the topic matter discussed here are not included.

  1. Extensible Markup Language (XML): http://www.w3.org/XML/
  2. XML-Signature Syntax and Processing: http://www.w3.org/TR/xmldsig-core/
  3. RSA Laboratories | Cryptography FAQ: http://www.rsasecurity.com/rsalabs/faq/index.html
  4. Counterpane Labs: Applied Cryptography (Bruce Schneier): http://www.schneier.com/book-applied.html
  5. RSA Security: http://www.rsasecurity.com/
  6. WS-Security Specification Index Page: http://msdn.microsoft.com/library/en-us/dnglobspec/html/wssecurspecindex.asp
  7. MD5: http://www.ietf.org/rfc/rfc1321.txt
  8. SHA1: http://csrc.nist.gov/publications/fips/fips180-1/fip180-1.txt
  9. XML Schema: http://www.w3.org/XML/Schema
  10. Strong Name Tool (sn.exe): http://msdn.microsoft.com/library/en-us/cptools/html/cpgrfstrongnameutilitysnexe.asp
  11. Transform Algorithms: http://www.w3.org/TR/xmldsig-core/#sec-TransformAlg
  12. Canonicalization Algorithms: http://www.w3.org/TR/xmldsig-core/#sec-c14nAlg
  13. Enveloped Signature Transform: http://www.w3.org/2000/09/xmldsig#enveloped-signature
  14. SSL 3.0 Specification: http://wp.netscape.com/eng/ssl3/
  15. MSIL Disassembler (ildasm.exe): http://msdn.microsoft.com/library/en-us/cptools/html/cpconmsildisassemblerildasmexe.asp

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Heath Stewart
Program Manager Microsoft
United States United States
Heath Stewart is a happily married software engineer originally from the Midwest and a graduate of Iowa State University. Heath start programming early in life and enjoys continuous research and development in new languages, frameworks, and platforms. Fluent in many different programming languages, he has developed many large-scale software solutions for companies in different areas, such as Internet filtering, intrusion detection systems, production management systems, and web applications for various purposes. He also enjoys photography.
 
Currently, Heath is a Program Manager in the Visual Studio Professional Deployment Experience (VSPro DEX) team at Microsoft. Previous to his employment, he was a Microsoft MVP for Visual C#.
 
He is also a CodeProject protector and is happy to help the development community.
Follow on   Twitter

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMy vote of 5memberMizan Rahman12-Apr-13 1:59 
Hi,
 
I'm littile bit unsure about "key container". Is it a storage on OSs RAM or OSs disk. Microsoft seems to say that the "key container" is the most secured location to store private keys. Another thing is that I have to specify a name for the "key container", does it have to unique? and the name of the contianer is in the DLL (.net assembly), so diassemblying the DLL could reveal the container name, right? which in turns could retrive private key !?
 
Any response would be appriciated?
 
Regards,
Mizan
GeneralMy vote of 5memberFormer Big Iron Guy13-Aug-12 12:15 
Good, useful, application I plan to use in an upcoming project.
GeneralMy vote of 5membermanoj kumar choubey28-Feb-12 18:28 
Nice
QuestionSign XML Documents with Digital Signaturesmemberdufduf9-Nov-11 2:51 
I`m looking for help with writing a program for electronic signature of XADES-BES for the xml file. Magazine of the certificate is available from the IE browser. How do it in C++ Builder?
QuestionSignature invalidmemberlalaaa25-Jun-11 23:40 
to run the code i wrote the commands
sn.exe -k KeyFile.snk
ExtractPubKey.exe > PubKey.xml
Sign.exe Request.xml > license.xml
Verify.exe license.xml
 
but the output "Signature invalid"
 
can u help me???
AnswerRe: Signature invalidprotectorHeath Stewart27-Jun-11 15:10 
Did you install the key into a container as mentioned right after generating the key pair?
sn.exe -m y
sn.exe -i KeyFile.snk CodeProject
This is what Verify.exe uses to determine if the publisher of the signed has is valid. Merely verifying the stored hash is the same as the actual hash is not secure if there is no way to verify who generating the hash (the publisher).
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Program Manager II
Visual Studio Professional Deployment Experience
Microsoft
 
[My Articles] [My Blog]

GeneralSignature verification failingmemberSherbeiah Tishbi28-Jan-11 10:09 
Hello
 
I am facing a weird issue. I have a vendor who signs a SAML using OpenSAML (java library) and sends to me for SSO. When I try to Verify the signature it fails. When I use his cert and generate the SAML then I can verify it. Could you please help me to understand the issue? I have stringent deadlines and issue doesn't seem to go away.
 
Thanks
Sherebyah
GeneralRe: Signature verification failingprotectorHeath Stewart29-Jan-11 7:31 
There's not a lot to go on there. What sort of error do you get? Do you have the parent chain of public certs installed on your machine that the vendor signs with? Apart from that, you may want to ask on a forum for OpenSAML. This article is about making your own implementation and I really don't know anything about OpenSAML.
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Program Manager II
Visual Studio Professional Deployment Experience
Microsoft
 
[My Articles] [My Blog]

GeneralPossible security flaw [modified]memberOndřej Linhart19-Jun-10 8:14 
What if someone modifies public key in assembly? Then this same person can sign and successfully verify his own license file. I have experimental strong named console application in which is embedded resource - public key in XML format. If I modify this public key using Hex Workshop, application works like before with no security exceptions. How to prevent this modification?
 

 
-- Modified Saturday, June 19, 2010 2:24 PM
GeneralRe: Possible security flawmemberratzinho8710-Jul-10 12:53 
I am having the same concerns. I know this system is not hacker-proof, but I think the workaround you described is quite basic. What I am thinking about is:
* create a licensing check assembly which contains the public key as an embedded resource
* obfuscate the assembly
* sign the assembly with a strong name
* in the main application, before loading the licensing assembly, check if it has the proper strong name ( http://blogs.msdn.com/b/shawnfa/archive/2004/06/07/150378.aspx[^] )
 
So, you end up with a hacker being forced to remove the strong name from the licensing assembly, change the obfuscated public key, then hack your main application in order to remove the strong name check. And by doing this, you make it as hard as hacking your application in order to change that "if LicenseIsInvalid() then Exit()" line of code.
 
As I am only trying to keep the honest people from hacking the application, this might do.
GeneralRe: Possible security flawprotectorHeath Stewart19-Jul-10 2:08 
The CLR already does that for you. When you compile your source with assembly references (which links) the entire strong name of reference assemblies is stored in the assembly manifest - including the public key token. Changing the pulic key changes the public key token (for everything except core runtime assemblies, which are handled specially (see the CLI specification for more informatin).
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Program Manager
Deployment Technology Group
Microsoft
 
[My Articles] [My Blog]

GeneralMy vote of 1memberabmv26-Feb-10 4:06 
does not f***ing work and the sh*t author did not update to explain the problems
GeneralRe: My vote of 1memberJohn C17-Mar-10 19:05 
You are not only ignorant and rude, you're incorrect and you have a lot of balls to make such a claim on an article that's stood the test of time.

Yesterday they said today was tomorrow but today they know better.
- Poul Anderson

JokeRe: My vote of 1memberThesisus21-Apr-10 8:18 
I was just thinking he must be super clever to be the first whose noticed... Wink | ;)
Fear not my insanity, fear the mind it protects.

QuestionGot a basic problemmemberSom Shekhar31-Jul-09 21:02 
Thanks for a nice article. (my vote of 5).
 
My problem comes from a basic tweak that i always did. Any expiration date based expiration can usually be tweaked by changing the system date.
 
Now, even if in the license file, i provided the expiration date, the user could change the system date to bypass it.
 
Any suggestions?
AnswerRe: Got a basic problemmemberPaulo Zemek26-Oct-09 7:29 
I am only a reader of the article, but I have a solution:
- When exiting the application (or in another moment) log the Date and Time.
If at the next login the date/time is lower than the saved one, consider it as "corrupted".
 
Of course, the type of system also determines if the tweak can be used. After all, many systems with printing mechanisms must print the date/time of printing, so the tweak is invalid.
Also, if is good to "recheck" date/time on key functionalities, so changing the date time and changing it back after loading the system does not work.
GeneralRe: Got a basic problemmemberSom Shekhar26-Oct-09 7:35 
Your answer is correct but the problem is that saving that data in a file serves no benefit. Consider what I will do:
 
0. Install the application and run.
1. Find out from any capable resource monitoring tool that what files does the application access.
2. Copy the files and save it in a safe place
4. When the program expires, turn the date back to Initial date
5. Replace all files copied previously.
 
Now, the program cannot find out if the date is tweaked because it has the wrong reference file.
 
Suggest something.
GeneralRe: Got a basic problemmemberPaulo Zemek26-Oct-09 12:55 
Well, if the program in question requires the date for the user data the tweak will not be useful, but if that's not the case, I must say the only solution is to connect to the internet, if this is an option.
In this case, you can connect to a remote server that tells if the license is still valid or not.
 
Well... maybe there is another method, but a little more complex. Create a secondary process to get the reference file and save it, so many monitor programs will not know it exists, and them communicate via IPC with it.
GeneralRe: Got a basic problemmemberSom Shekhar27-Oct-09 16:26 
Yes. if the the program requires the date, problem is sorted.
 
Connecting to internet is not an option.
 
I was thinking of possibilities of a partition/folder/file which is not possible to copy/rewrite without a
key. TrueCrypt can do that but I don't know of any libraries that can access it from within the code.
 
DateStamp was another possibility but that can be tweaked very easily.
 
Isn't there any increment based counter (like ticks) in Windows or Motherboard which cannot be tweaked/changed? Big Grin | :-D
 
let me clarify that I am not worried about it being broken (Anything can be broken for sure. Its only a matter of time). I also believe that if someone is smart enough to break it, they are worthy of using it too. However, these instructions should not easily be transferable. So, it has to be a difficult method to break it.
 
Because once the software is in use, changing security system is a difficult task especially if you work with versions.
AnswerRe: Got a basic problemmemberJohn C17-Mar-10 19:07 
At some point you have to consider that any system is really only going to keep honest people honest. There are ways to circumvent anything and you can easily start into the zone of diminishing returns by trying to be too clever against determined, intelligent people.

Yesterday they said today was tomorrow but today they know better.
- Poul Anderson

GeneralRe: Got a basic problemmemberSom Shekhar17-Mar-10 19:56 
There is an old saying... "Locks are for honest people... To thieves, they are invitations"
 
I know that all licensing mechanisms can be broken. But they should rather be done by making a change in the program and not in the environment.
 
Changing the system date doesn't make any difference in the software. It makes changes only for the environment. One can write a wrapper for a software that provides a fixed DateTime.Now to my software.
 
Here, I wanted to know if there is a possibility to capture the real date time? is it Ticks? or some other processor based number that keeps changing and doesn't depend on the operating system?
GeneralRe: Got a basic problemmemberJohn C17-Mar-10 20:14 
Som Shekhar wrote:
or some other processor based number that keeps changing and doesn't depend on the operating system?

 
Interesting. I'm not aware of this possibility but my hardware knowledge is a little out of date.
 
I've always treated the system date as unreliable when it comes to these matters, however I have the great benefit of having software that, to the user, it's critical that the correct date and time is used because it involves scheduling to a high degree so for me it's not so much an issue as I can see it would be in other circumstances.

Yesterday they said today was tomorrow but today they know better.
- Poul Anderson

GeneralRe: Got a basic problemmemberSom Shekhar17-Mar-10 20:25 
Thats correct. I have a similar software which highly depends on the Dates and hence need not worry about changing dates.
 
The other possibility could be to print a date on every report. Thus, any reports printed will be outdated.
 
Also, if the software is LAN Based and not a single machine software, the problem is automatically sorted to a large level.
 
I am only considering it for some software that I am planning in a month or two, that will be running on a single machine with no internet Frown | :(
 
Hardware based counter could only be the way.
GeneralRe: Got a basic problemmemberDaniele Barzotti12-May-10 10:42 
Som Shekhar wrote:
Here, I wanted to know if there is a possibility to capture the real date time? is it Ticks? or some other processor based number that keeps changing and doesn't depend on the operating system?

 
Hi,
me too, after have read the article, I ask myself the same thing.
Usually I use hardware keys for my software and I store the period of usage in the key.
But, maybe, here we have a trusted XML file.
 
I think we can store the "amount of time the application is open" into the file and re-sign it.
If the user changes it, he invalidate it.
 
So we can use the file like a secure storage?
 
Cheers,
Daniele.
GeneralRe: Got a basic problemmemberSom Shekhar12-May-10 18:31 
The problem is that the Signature is the key to the validity of the file. Which is saved somewhere on the disk (Within the XML file or outside).
 
Now, consider this.
 
Status of files when you run the program in valid duration:
 
0. System Date: Valid Date
1. XML file (signed)
2. Signature hash (In the same file or a different location)
 
Now, if I copy these two files for later use and once the program expires, replace them and change system date, there is no way application can recognize the change and hence will work as valid.
 
Daniele Barzotti wrote:
"amount of time the application is open"

 
Now, anything which is saved in the xml file is of no use.
GeneralUsing "using" with an RSACryptoServiceProvider object [modified]memberdelftred16-Jun-09 16:56 
Note that Microsoft recommends wrapping the RSACryptoServiceProvider object with a using statement. See:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
 
modified on Tuesday, June 16, 2009 11:18 PM

GeneralNon-Constant public/private key pair from *.snk file!memberRobert Foster8-Jun-09 4:19 
I've come across a problem while using this solution to do with the private and public key pair generated using sn.exe
 
I created the key pair and installed in the machine key store (sn -m y then sn -i licenses.snk AppName), and exported my public key using dotnet into an xml file. This has been embedded in the applications, and is all fine and good for xml documents signed using it's corresponding private key.
 
Now, the problem comes when I try to use the licensing application to sign a license. Initially this worked fine, but the next day I noticed the validation code was reporting an invalid signature if I signed a new license and tested it with the embedded public key from the day before.
 
The same issue arises on a separate computer. If I generate a signed license xml file on another computer, it's reported as invalidated using the embedded public key.
 
After some testing, I found that not only that, but every time I removed and re-installed the private/public key pair into the machine's key store, it somehow alters the private/public pair, and the exported public key is different every time! It doesn't matter whether I use the sn.exe utility or install the key programmatically, same result. Any ideas? because at this point, using sn.exe to generate the key pair seems to be broken?!?
QuestionVerify always failsmemberChris515030-May-09 17:19 
Hello, I'm new to this so I must be doing something wrong. I am able to sign the xml doc but every time I try to verify it fails. Any sugestions for where I might ve going wrong?
Thanks
- Chris
AnswerRe: Verify always failsprotectorHeath Stewart31-May-09 23:10 
Make sure you using the right key exchange:
CspParameters parms = new CspParameters(1);
parms.Flags = CspProviderFlags.UseMachineKeyStore;
parms.KeyContainerName = "CodeProject";
parms.KeyNumber = 2;
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(parms);
Console.WriteLine(csp.ToXmlString(false));

 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

GeneralRe: Verify always failsmemberChris51502-Jun-09 15:29 
That's what I had in my code. I finally changed it to the following (per this article http://msdn.microsoft.com/en-us/library/ms229950.aspx[^]) and then I was able to verrify.
 
CspParameters parms = new CspParameters();
parms.KeyContainerName = "CodeProject";	
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(parms);
 
I'm concerned that I might be looking at the wrong key because your initial example was very explicit about using the second key. Thoughts?
QuestionWhat happens when the Cert expires?memberColinMaunder5-Mar-09 1:29 
Nice article, we are considering implementing something along these lines.
 
I'm a little unclear about what will happen when the cert expires.
 
Will the licenses issued using a cert which has now expired continue to work.
ie
cert valid for 2008.
license X issues in 2008
license X installed 2009 - will it still work?
 
Also will the license server be able to continue to create licenses with the expired cert?
 
Thanks
AnswerRe: What happens when the Cert expires?protectorHeath Stewart11-Mar-09 15:01 
You'll want to incorporate timestamp verification just like with Authenticode signatures. This verifies when the certificate was signed (and the date is encrypted like a signature hash) so the client license can remain valid. Of course, if you want to force renewals you wouldn't verify timestamps.
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

QuestionAny literature?memberMember 77975811-Jan-09 2:28 
Thanks for this great article. I have to write thesis about this topic. Are there any new books / articles about it?
 
Roland
GeneralThanks, such a useful article.memberJon Mirtschin27-Dec-08 16:14 
Thanks Heath for such a great article to introduce a method for licensing software.
 
I searched for hours for an article/tutorial such as this to allow me to distribute/test a small program I've been writing, without giving it away. I was close to signing up for a commercial service (but didn't want the expenditure for something I might never be able to recoup). By studying your article, I'm now able to implement my own version of a xml license file.
 
Thanks again,
 
Jon
GeneralVery cool!memberDr.Luiji18-Dec-08 8:03 
Good idea and very creative work.
 
Dr.Luiji
 
Trust and you'll be trusted.
 
Try iPhone UI [^] a new fresh face for your Windows Mobile, here on Code Project.

AnswerSupermemberdimitris.dpant20-Nov-08 10:25 
I've been surfing the entire web for such a solution and your article is the only one that both explains the whole matter in a way of unprecedented clarity and suits my needs 100%. Thank you so very much for this. Super. Period.
QuestionComputer policy that can stop CheckSignature?memberajhuddy7-Oct-08 9:39 
I been successfully using this technique for a few years now, and it has worked flawlessly at dozens of sites (which equals hundreds of computers).
 
Recently, I have found that the SignXml.CheckSignature call is always returning false at a few client sites. Is there a Windows policy, or security setting that can cause this API to always return false?
 
At the one site where it fails, if they do not install their standard set of 'domain' software before running our application, the CheckSignature does work.
 
Any ideas?
QuestionNative code perhaps?membertonyt11-Aug-08 6:14 
I don't understand how one can suggest that digitally signing and verifying XML in managed code (verses native code) is feasable, Is it really?
 
Does anyone know of a native code equivalent for this?
GeneralRe: Native code perhaps?protectorHeath Stewart13-Aug-08 6:18 
I do actually mention that you can increase the difficulty by doing something similar in native code. But that's all you can do: increase the difficulty. For a native application, I could - though more difficult, not impossible - hook the procedure that validates the signature and just always return that it's valid. It's just making it more difficult.
 
As stipulated in the article, you have to figure who your audience is.
  • Writing code for the average user? This article should serve well.
  • Writing code for government agencies? Why are you looking for solutions in a public forum like this?
 
Manage code would still require that one disassembles, changes, reassembles, and re-signs ALL assemblies higher in the stack. So implementing this in an assembly loaded by your app does mean they would have to resign more.
 
This posting is provided "AS IS" with no warranties, and confers no rights.

NewsASP.NET Signaturesmemberjay_dubal13-Jul-08 23:45 
Ever thought of integrating user signatures in your web pages. So as to allow users to sign documents online! Visit http://mysignature.brinkster.net for ASP.NET Signature Application, Allow users to sign documents online
Question[Message Deleted]memberGreg Cadmes7-May-08 6:41 

AnswerRe: Preserve whitespace?protectorHeath Stewart17-May-08 8:43 
I don't even mention whitespace in my article that I can find, and clearly in the posted examples whitespace is preserved. Is some there some specific text you can quote?
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

GeneralAmazing how this article lives on...memberMember 431598214-Apr-08 8:13 
You must have done a good job, the article still lives...
 
I had a question about deployment. I was running this all locally, all good. I go to deploy to my production server.
 
I'm putting the Signing stuff in a WebService, which now causes problems because ASPNET doesnt have access to the keystore. For the life of me I can't figure out how to grant access.. I've looked at the winhttpcertcfg.exe utility, wchich should work, but it can't seem to find my certificate. / key.
 
So this is the confusion I guess I'm having.
 
When I use sn -k KeyFile.snk
Then: sn -i KeyFile.snk MyKey
 
It installs fine, but I can't see this installed key anywhere. If I go into my Certificates MMC Snap-in, it's no-where to be found. and if i use winhttp:
 
winhttpcertcfg -g -c LOCAL_MACHINE\Root -s MyKey -a ASPNET
 
It returns saying nothing. Am I getting confused between certificates and private/public keys ?
AnswerRe: Amazing how this article lives on...protectorHeath Stewart19-Apr-08 9:30 
Unless you already enable machine-store access using sn.exe -m y, all you did was add the certificate to your store - not the machine store, for which the ASPNET account that ASP.NET runs under by default (actually, I think they changed that in recent versions - but it still isn't your account) cannot access.
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

GeneralSome comments.memberGiorgi Moniava11-Apr-08 2:08 
Hi Heath(or Stewart) Smile | :) .
 
I just voted a 5 for your article, since you wrote a well explained practical tutorial about using XML signatures for Product Licencing. However, there are several (umnetioned) things that I think would increase the technical strength of you article: (1) What are the main threats in the Product Licencing mechanisms? (2) To what extent does "your" current product licencing mechanism address these threats, and (3) How does "your" licensing mechanism fit in the global picture of other product licensing mechanisms, i.e. what are the differences in approaches, pros and cons, etc.
 



"Success is the ability to go from one failure to another without loss of enthusiasm." - W.Churchill



 
modified on Friday, April 11, 2008 9:30 AM

GeneralRe: Some comments.protectorHeath Stewart19-Apr-08 9:28 
I pretty much covered all that in my article. I pointed out that, as with any licensing mechanism, anyone that can decompile or even disassemble your app can get around the licensing calls. All one can do is obfuscate such calls or make it hard to reverse engineer, but it has the same problems as with DRM: the code (or even private keys) are on your system; all you have to do is workaround it. This is meant to be fool-proof. That is, most people wouldn't know how to get around this.
 
Of course, managed apps complicate things since they are easy to disassemble using tools like ildasm.exe that even ship with the .NET Framework SDK.
 
This was only meant as an introduction to XML digitial signatures and not a full working solution - something else I also pointed out in my article. You could build upon this by doing a Web Service for which requests are sent up and signed responses are sent back, similar to other PKI request/response systems.
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

GeneralProblem when I have change my Sign XML application to New PCmemberPrasertHong23-Feb-08 22:57 
This is a great articles. My application have successfully use this technic for a number of year that mean user have to send RequestLicense.xml to me to sign a valid license.xml, then I send License.xml file back to them for copying into thier machine for grant of S/W used.
 
But the problem occured when I had move my SignLicense Application to a new PC, I had installed my old Key-Pair "sn -i KeyFile.snk CodeProject" into my new PC, but my old distributed application, with old publickey.xml, is still could not verify the license.xml that was signed from my new PC.
 
Could you please advice of how to solve this problem? Frown | :(
GeneralRe: Problem when I have change my Sign XML application to New PCprotectorHeath Stewart24-Feb-08 16:00 
Did you install it into the user store or the machine store? Can you sign on this new machine without error?
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]

GeneralRe: Problem when I have change my Sign XML application to New PC [modified]memberPrasertHong25-Feb-08 16:17 
Thank for your kind of replying my issue.
 
I install it into the Macchine store, as you recommended, with "sn -m y" & "sn -i KeyFile.snk CodeProject".
 
Yes, I can sign the requesteLicense.xml without error. But when I verify the signature with "sxml.CheckSignature(csp)" it's return false "Failed: Signature invalid".
 
Please advice!
 
modified on Monday, March 3, 2008 9:43 PM

Generalgetting the computer SID...memberJochen Wendebaum20-Feb-08 23:16 
Hi,
 
I am looking now for some code to retrieve the computer SID since two days, and all I find is the Sysinternal's NewSID and the psgetsid applications. I want to do it in my sourcecode without the need to have an additional DLL.
 
The provided proplanner.dll (thanks for that!) works nice, but I would like to use the source code directly in my app.
 
Any hints on where to find some information about retrieving the SID myself??
 
Thanks for the help!
 
Jochen

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130617.1 | Last Updated 23 Nov 2005
Article Copyright 2003 by Heath Stewart
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid