Persits Software, Inc. Web Site
Main Menu:  Home |  News |  Manual |  Tasks |  Object Reference |  Crypto 101 |  FAQ |  Download & Buy |  Clients |  Live Demo |  Contact
 Navigator:  Home |  Tasks |  Manage Certificates and Certificate Stores
Send Secure Mail Create and Verify Digital Signatures
  Manage Certificates and Certificate Stores
A digital certificate is a data structure that stores someone's personal information such as a name or email address, together with this person's public key. This data is signed by a certification authority (CA) who issued the certificate.

A certificate can exist in a file or certificate store in the system registry.

It is highly recommended that you install the CertMgr.exe application as it will make the debugging of certificate-related applications easier. CertMgr.exe is included in the Microsoft Platform SDK CD ROM. If you are running IE 5.0, CertMgr.exe is already installed on your machine. To invoke it, open IE 5.0, go to Tools/Internet Options, select the Content tab and click the "Certificates" button.

  Opening a Certificate Store
Certificates stores are kept in the system registry under the keys HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates and HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates.

Each user has a MY certificate store which contains his/her personal certificates. The ROOT store contains certificates of the most trusted certification authorities. The CA store contains less frequently used certification authorities. The AddressBook store contains other people's certificates.

In AspEncrypt, a certificate store is represented by the CryptoStore object. An instance of this object is created via CryptoManager's OpenStore method, as follows:

Set Store = CM.OpenStore("MY", False )

The OpenStore method accepts two arguments: the name of the store and a flag specifying whether the store is located under the HKEY_LOCAL_MACHINE (if set to True ) or HKEY_CURRENT_USER (if set to False) section of the system registry. The following rule of thumb applies in most cases: if you are using AspEncrypt in a stand-alone application (such as a VB program) you should specify False for the second parameter. If AspEncrypt is used from an ASP or ISAPI application, you should specify True.

If the store name passed as the first parameter does not exist, the method will create it.

In an ASP environment, if anonymous access is enabled, an attempt to open a store will probably result in an Access Denied error. To avoid this error, impersonation of an admin account should be used, as follows:

<%
Set CM = Server.CreateObject("Persits.CryptoManager")
CM.LogonUser "domainname", "adminuser", "xxx"
Set Store = CM.OpenStore("MY", True)
%>

For the LogonUser method to work successfully, the current user must have the "Act as Part of Operating System" privilege.

  Enumerating Certificates in a Store

The CryptoStore object has a property, Store.Certificates, which returns the collection of CryptoCert objects which represent certificates residing in this store. The following code snippet enumerates all certificates in the ROOT store of the HKLM section of the registry:

<%
Set CM = Server.CreateObject("Persits.CryptoManager")
CM.LogonUser "mydomain", "adminuser", "xxx"
Set Store = CM.OpenStore("ROOT", True)
For Each Cert in Store.Certificates
   Response.Write Cert.Subject.Name & "<P>"
Next
%>

A more complete certificate store example can be found in the file Samples\cert_stores\certs.asp of the installation.

  Examining Certificates using CertMgr.exe

Run CertMgr.exe (included with IE 5.0 or available from Microsoft Platform SDK.) You will see a screen similar to this:

If you double-click on one of the certificates in the list, the certificate property sheet comes up:

  Obtaining an Instance of the CryptoCert Object
AspEncrypt provides the CryptoCert object to represent a certificate. There is a number of ways to obtain an instance of the CryptoCert object. We have already learned how to use the CryptoStore.Certificates collection to enumerate all certificates in a store. The Certificates collection also allows you to obtain individual certificate objects as well.

Just like any COM collection, Store.Certificates supports a default Item property which accepts an integer or string index. The string index specifies a certificate's serial number as displayed by the certificate property sheet shown above. For example, to obtain a CryptoCert object representing the Thawte Freemail Member certificate shown on the screenshot above, we can say:

Set CM = Server.CreateObject("Persits.CryptoManager")
Set Store = CM.OpenStore("MY", False)
Set Cert = Store.Certificates.Item("012E 78") '
Paste Serial Number here

A certificate's serial number can simply be copies and pasted from the certificate property sheet. Since Certificates.Item is a default property we can omit the word Item. Also, this property ignores spaces in the index value, so the following code is acceptable as well:

...
Set Cert = Store.Certificates("012E78") '
No spaces is OK too

A CryptoCert object can also be created from a certificate stored in a file. There are two most commonly used file formats for storing certificates: DER-Encoded X.509 (.cer or .crt) and Cryptographic Message Syntax Standard PKCS #7 (.p7b). The DER-Encoded format can be in the binary or Base64-encoded form.

AspEncrypt imports a .cer file into a CryptoCert object using the CryptoManager.ImportCertFromFile method, as follows:

<%
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Cert = CM.ImportCertFromFile("d:\somecert.cer")
' Do something with the Cert object
%>

The ImportCertFromFile method automatically determines whether the file is in a binary or Base64-encoded form.

To import a certificate in the PKCS#7 format, the CryptoManager.ImportStoreFromFile method should be used as a file in this format may contain several certificates at once. Once a CryptoStore object is created from the file, individual certificates can be obtained from it using the Certificates collection as explained above. For example:

<%
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Store = CM.ImportStoreFromFile("d:\somecert.p7b")
Set Cert = Store.Certificates(1) '
We use an integer index here
' Do something with the Cert object
%>

There is also the PKCS#12 (also known as PFX) format for storing certificates together with their respective private keys using password protection. See the section Support for PKCS#12 (a.k.a. PFX) Format below for details.

  Accessing Client Certificates via ASP's Request.ClientCertificate
You may configure a virtual directory or the entire web site to accept (or require) client certificates. When trying to access such a resource, a user will be prompted by the browser to select one of his client certificates. A certificate selected this way will be uploaded to the server and become available to server-side ASP script via the Request.ClientCertificate collection.

AspEncrypt 1.1 is capable of capturing the Request.ClientCertificate information and save into a file or import it into a CryptoCert object. This is done with the help of the CryptoBlob object as follows:

<%
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Blob = CM.CreateBlob
Blob.Binary = Request.ClientCertificate("Certificate")
If Len(Blob.Hex) > 0 Then
   Set Cert = CM.ImportCertFromBlob(Blob)
   
' Do something with the Cert object
Else
   Response.Write "No certificate received."
End
%>

Starting with Windows 2003 and IIS 6.0, due to changes in the format of data returned by Request.ClientCertificate, the direct assignment of the certificate information to Blob.Binary should be replaced by a two-step process via a temporary variable, as shown below. Otherwise, the error ASN1 bad tag value met will be generated.

<%
...
Set Blob = CM.CreateBlob
Temp = Request.ClientCertificate("Certificate")
Blob.Binary = Temp
...
%>

  Browsing the Issuer and Subject Properties
Some CryptoCert properties such as Cert.Version, Cert.SerialNumber, Cert.NotAfter, Cert.NotBefore, etc. are fairly self-explanatory. Others do deserve our attention.

The Issuer and Subject properties return CryptoName objects which contain information about the issuer authority and the entity to whom the certificate is being issued, respectively. The CryptoName object has a default Item property which accepts an optional index argument. For the Thawte certificate shown above the expression Cert.Issuer.Item (or simply Cert.Issuer as Item is the default property) returns the following string:

C=ZA
S=Western Cape
L=Durbanville
O=Thawte Consulting
OU=Thawte PF RSA IK 1998.9.16 17:55
CN=Thawte Personal Freemail RSA Issuer 1998.9.16

The expression Cert.Subject returns the following string:

CN=Thawte Freemail Member
E=persits@vni.net

You can see that a certificate's Subject and Issuer properties consist of several tagged components separated by a CR/LF sequence. The most common ones are CN (common name), E (email), O (organization), OU (organizational unit), L (locale), S (state), and C (country). The CryptoName object allows you to obtain individual components of a name by specifying the appropriate tag as Item's argument. For example, the expression Cert.Issuer("CN") returns

Thawte Personal Freemail RSA Issuer 1998.9.16

The CryptoName object also provides the property Name, which looks for the components CN, OU, O, and E in this order and returns the first one found.

  Obtaining a Certificate's Private Key
Each of your personal certificates installed on your machine has a private key associated with it. This private key is stored in a key container in the system registry and can be obtained by opening the appropriate cryptographic context. This allows you to use your personal certificates to, say, generate digital signatures. Certificates from other people and certification authorities obviously don't have associated private keys (on your machine, that is).

The CryptoCert object provides a Boolean property, PrivateKeyExists, which returns True if this certificate has an associated private key on this machine. You can obtain the corresponding certificate context by calling the property PrivateKeyContext which returns an instance of the CryptoContext object.

The following code snipped was run against the Thawte certificate shown above:

' VB Code
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Store = CM.OpenStore("MY", False)
Set Cert = Store.Certificates("012E 78")
Set Context = Cert.PivateKeyContext
MsgBox Context.Container

The result was "Administrator". This means that the private key corresponding to this certificate is located under the key

HKEY_CURRENT_USER\Software\Microsoft\Cryptography\UserKeys\Administrator.

With AspEncrypt, you can also set the private key context of a certificate using the Cert.SetPrivateKeyContext method. This method can be useful when issuing your own certificates. However, you should be careful with this method as you may accidentally make a certificate point to the wrong private key, that is, not the private key this certificate's public key corresponds to.

  The Underwater Rocks of CryptoAPI
AspEncrypt is based on the CryptoAPI. Under certain conditions, some CryptoAPI functions display warning messages, such as this one:

Th conditions under which the CryptoAPI displays warning messages include, but are not limited to, the following:

  • An attempt to add a certificate to, or remove a certificate from, the HKEY_CURRENT_USER-based ROOT store.
  • An attempt to generate a signature with a private key created with the security flag set to USER_PROTECTED and stored in an HKEY_CURRENT_USER-based key container.
  • An attempt to decrypt an encrypted message with a private key created with the security flag set to USER_PROTECTED and stored in an HKEY_CURRENT_USER-based key container..
Performing these tasks with AspEncrypt in an ASP environment will result in hanging up the web server. However, this is not the case for stores and private keys located in the HKEY_LOCAL_MACHINE section of the registry.
  Moving Certificates with their Private Keys to HKEY_LOCAL_MACHINE
When using AspEncrypt in an ASP environment to perform private key-related operations such as generating signed mail messages, you should move the personal certificates you want to use from the HKEY_CURRENT_USER to HKEY_LOCAL_MACHINE section of the registry. This way you make these certificates readily available to your ASP application and remove the USER_PROTECTED flag from the corresponding private keys to avoid the "underwater rock" problem just described.

To facilitate the moving procedure, AspEncrypt provides a method, Cert.TransferToLocalMachine, which moves the certificate to the specified HKEY_LOCAL_MACHINE store together with its private key.

The following VB code snippet does the job:

Dim Cert As ICryptoCert
Dim Store As ICryptoStore
Set Store = CM.OpenStore("MY", False) '
Open MY store at HKCU
Set Cert = Store.Certificates("012E 78") '
Obtain my Thawte cert
Cert.TransferToLocalMachine "MY" '
Transfer to MY store at HKLM

The AspEncrypt installation includes CertMover.exe, a sample VB application with the source code included which you can use to transfer certificates from the HKCU to HKLM sections of the registry. This application can be found in the directory \Samples\cert_stores\CertMover of the installation.

For a private key to be movable (or otherwise exportable), it must have been created with the CRYPT_EXPORTABLE flag set. Otherwise, when attempting to use the CertMover application, you will receive a Bad Key error message:

The certificate enrollment procedures implemented by VeriSign and Thawte do not normally give you the opportunity to specify the CRYPT_EXPORTABLE flag when your private key is being created. As a result, you cannot move your certificate to HKEY_LOCAL_MACHINE, and you end up not being able to use it for digital signing in an ASP environment.

Therefore, if you want to be able to send digitally signed mail from ASP, you must take the process of generating a private key and corresponding Certificate Request file into your own hands. The next section explains how to do it.

  Obtaining a "Friendly" Certificate from VeriSign™
We have provided an on-line Web page which contains everything you need to
  • create a private key with the CRYPT_EXPORTABLE flag set;
  • generate a certificate request file (CRF) necessary to apply for a certificate from a certification authority;
  • send the CRF to VeriSign™ in order to obtain a client certificate which you will be able to use for digital signing in the ASP environment;
  • install the certificate received from VeriSign.
This page uses the Microsoft XEnroll ActiveX control and client-side VB script, so it requires Internet Explorer 4.0+.

This page is available on the AspEncrypt.com web site at www.aspencrypt.com/get_cert.htm. Follow the step-by-step instructions to obtain a certificate which you will be able to move to the HKEY_LOCAL_MACHINE section of the registry and use it to generate digitally signed mail. Secure mail is our next topic.

  Support for PKCS#12 (a.k.a. PFX) Format
Starting with version 2.0, AspEncrypt supports a special file format that stores certificates together with their private keys. Private key information in such a file is protected with a password. This file format is known as PKCS#12, or Personal Information Exchange (PFX). PFX files usually have the extensions .pfx or .p12.

Thanks to AspEncrypt's support for PFX format, you no longer need to go through the trouble of moving a certificate to the HKEY_LOCAL_MACHINE section of the registry to get hold of its private key. All you need to do is export your certificate into a PFX file and place this file on the server where AspEncrypt can access it.

To export a certificate from your personal certificate store into a PFX file, open IE or Netscape and bring up the list of your personal certificates. Select a certificate and choose "Export". IE will ask you whether you want to export the private key with the certificate, and you should say "Yes." Netscape always exports the certificate's private key. You will also be asked to specify a password that will be used to encrypt your certificate's private key information. You will be using this password in your code to open the PFX file.

To retrieve a certificate from a PFX file with AspEncrypt, use the method CM.OpenStoreFromPFX which returns a CryptoStore object representing all certificates contained in the PFX file, as follows:

...
CM.RevertToSelf
Set Store = CM.OpenStoreFromPFX("c:\path\file.pfx", "password")
Set Cert = Store.Certificates(1)
' do something with the certificate

IMPORTANT: The method OpenStoreFromPFX uses an undocumented CryptoAPI function PFXImportCertStore from the library Crypt32.dll. For this method to work under IIS 5.0, you must call CM.RevertToSelf prior to calling OpenStoreFromPFX, and your virtual directory's Application Protection option must be set to Low. Otherwise you will receive the error

Persits.CryptoManager.1 (0x800A0055)
The system cannot find the file specified.

A sample PFX file persits.pfx containing a test certificate can be found in the folder \Samples\cert_store of the AspEncrypt installation. The code sample http://localhost/aspencrypt/cert_stores/sign_pfx.asp computes a digital signature of a text string using a private key residing in this PFX file.

Create and Verify Digital Signatures Send Secure Mail

Search this Site
  This site is owned and maintained by Persits Software, Inc. Copyright © 2000 - 2010. All Rights Reserved.