|
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.
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.
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.
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:
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.
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
...
%>
|
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.
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.
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.
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.
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.
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.
|
|
|
|
|