|
Introduction
Peter Persits' article explains how Secure Multipurpose Internet Mail Extensions, or S/MIME, has come to rescue of e-commerce Web sites that need some order information to be contained in encrypted E-mail. Customers don't want to use automatic on-line credit card authorization, so order information instead is sent over an SSL-protected HTML form and credit card numbers are sent via encrypted E-mail for manual processing. If you are new to cryptography, I recommend starting with the crash course.
Scenario
Your company’s Windows NT server hosts multiple ASP-based e-commerce Web sites for your clients. Some clients do not want to use automatic on-line credit card authorization. They prefer to collect order information over a Secure Sockets Layer (SSL)-protected HTML form and receive credit card numbers via E-mail for manual processing. Naturally, they want the E-mail messages to be encrypted.
Your clients use one of the following E-mail applications: Outlook Express, Outlook 2000, or Netscape Messenger.
S/MIME to the Rescue
All three E-mail applications mentioned above have built-in support for Secure Multipurpose Internet Mail Extensions (S/MIME), a de facto secure mail standard developed by RSA Data Security. This format is based on public-key cryptography and X.509 digital certificates. Tto send someone an encrypted message you need to obtain the recipient’s certificate containing his/her public key and encrypt the message with it. Only the owner of the corresponding private key (the recipient) can decrypt such a message.
So, the good news is your clients will not need to purchase any additional software to read their secure mail, or install any plug-ins. They do, however, need to obtain a digital certificate from a certification authority (CA) such as Verisign™ or Thawte™. Verisign offers personal digital certificates for about $15 each. Thawte gives them out for free. The certificate enrollment procedure is not difficult, even for a technically challenged individual. Simply instruct your clients to point a browser of their choice to one of the certificate-dispensing sites, choose the “Personal/Individual Certificates” option on the Web page, and follow the instructions.
Once a certificate is obtained and installed, your clients are ready to receive encrypted E-mail. It is now your turn, as an ASP developer, to build a system that would send it. This article will show you how to develop an ASP-based system that generates secure mail in the S/MIME format using the Persits Software components AspEmail and AspEncrypt.
Getting Ready
- To debug your secure mail application, you will need a personal certificate of your own. Get one from a CA of your choice.
- Download a 30-day evaluation copy of AspEncrypt 1.1+ from www.aspencrypt.com. The installation program will install both the AspEncrypt and AspEmail components on your machine.
Building a Server-Side Certificate Repository
To send someone an encrypted E-mail message in the S/MIME format, your ASP script needs to have access to this person’s digital certificate.
There is, of course, plenty of ways a server-side certificate repository can be implemented. We can simply store certificate files in a file folder. Or we can place file paths and other information in a database table while keeping the actual certificate files on the hard drive. Finally, we can store everything, including certificate blobs, in the database.
For our sample application we will choose the "everything-in-the-database" approach, which eliminates the file name collision problem and simplifies backup. I use SQL Server 7, but the code we are about to write will work equally well with MS Access.
Let’s create a simple database with one table, which we will call Certs. The table has an identity column, a char(100) column to store the recipient’s E-mail address, a char(40) column to store a certificate’s hash value (to prevent duplicate occurrences of the same certificate), and an IMAGE column to store the certificate blob:
Figure 1
If you were to use MS Access, the corresponding data types would be Autonumber, Text (100), Text (40), and OLE Object, respectively.
Also, you will need to create a system DSN pointing to this database.
It’s time to write code that would allow your clients to upload their personal certificates into the repository. One way of doing this would be to have a user export his certificate to a file and then upload the file using a server-side upload component. A better approach would be to take advantage of ASP’s built-in Request.ClientCertificate collection, which brings the user’s client certificate to the server with very little effort on the user’s part.
Create a virtual directory on your Web site (let’s call it Certs) and configure it to require client certificates:
Figure 2
Place the following script (let’s call it SaveCert.asp) into this virtual directory. Now, when a user points his browser to the URL https://serveraddress/Certs/SaveCert.asp, the browser will ask the user to submit his client certificate by displaying the following dialog box:
Figure 3
The user selects his certificate and clicks OK. The script shown below will pick up the submitted certificate and save it into the database.
<HTML>
<BODY BGCOLOR="#FFFFFF">
<%
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Blob = CM.CreateBlob
‘ Obtain uploaded certificate
Blob.Binary = Request.ClientCertificate("Certificate")
‘ Export certificate into the database
Set Cert = CM.ImportCertFromBlob( Blob )
Email = Cert.Subject("e")
If Email = "" Then
Response.Write "Email address is not found."
Response.End
End If
set rs = Server.CreateObject("adodb.recordset")
rs.Open "CERTS", "dsn=crypto;uID=sa;PWD=;", 2, 3
rs.AddNew
rs("email").Value = Email ‘ save email
rs("hash").Value = Cert.Sha1Hash ‘ save hash value
rs("cert").Value = Blob.Binary ‘ save actual certificate
rs.Update
%>
<B>The certificate has been successfully uploaded into the database.</B>
</BODY>
</HTML>
Let’s examine this code snippet line by line.
The line
Set CM = Server.CreateObject("Persits.CryptoManager")
creates an instance of the AspEncrypt’s main object, CryptoManager. The next line
Set Blob = CM.CreateBlob
creates an empty object of the type CryptoBlob to store, format and otherwise handle binary data.
The following line
Blob.Binary = Request.ClientCertificate("Certificate")
takes the uploaded certificate (in a binary form) returned by the Request.ClientCertificate and places it in the CryptoBlob object.
The line:
Set Cert = CM.ImportCertFromBlob( Blob )
imports the uploaded certificate from the blob into a CryptoCert object. The purpose of the CryptoCert object is to store, query, and export certificates.
The following line
Email = Cert.Subject("e")
deserves special attention. Here we use CryptoCert’s Subject property to extract the E-mail address (tagged "e") from the certificate. Most personal certificates (including those issued by Thawte and Verisign) contain the owner’s E-mail address. Those that don’t should not be accepted into our certificate repository. That’s why the next line checks if the E-mail variable is empty, and if so, we end the execution of the script.
The next three lines use ActiveX Data Objects (ADO) to create a recordset object, connect it to the Certs database table, and add a new record:
set rs = Server.CreateObject("adodb.recordset")
rs.Open "CERTS", "dsn=CERTS;UID=sa;PWD=xxx;", 2, 3
rs.AddNew
The next line
rs("email").Value = Email
simply copies the E-mail address extracted from the certificate to the respective recordset field.
The line:
rs("hash").Value = Cert.Sha1Hash
retrieves the certificate’s SHA1 hash value and places it in the respective recordset field. We store certificate hash values along with the certificates to detect and prevent multiple occurrences of the same certificate in our database. Our code snippet could check whether the database already contains this certificate by looking up the respective hash value. For the sake of simplicity, this code fragment is omitted.
The line:
rs("cert").Value = Blob.Binary
copies the certificate blob from the CryptoBlob object to the recordset. And finally, the last line saves the new record to the database:
rs.Update
Sending Encrypted Mail
Now that we have a certificate repository in place, we can move on to the main piece: the script that generates encrypted messages in the S/MIME format.
The following code snippet does the job:
<HTML>
<BODY BGCOLOR="#FFFFFF">
<%
' Create an instance of AspEmail, initialize main properties
Set Mail = Server.CreateObject("Persits.MailSender")
Mail.Host = "mail.yourcompanyshost.com"
Mail.From = "me@yourcompanyshost.com"
Mail.FromName = "On-line Sales" ‘ Optional
Mail.Subject = "Order Information."
Mail.Body = "Message body." ‘ This will be encrypted
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Blob = CM.CreateBlob
set rs = Server.CreateObject("adodb.recordset")
rs.Open "select email, cert from CERTS where id=1", _
"dsn=crypto;uID=sa;PWD=xxx;", 2, 3
If Not rs.EOF Then
Mail.AddAddress Trim(rs("email"))
' import certificate from blob
Blob.Binary = rs("cert").Value
Set Cert = CM.ImportCertFromBlob( Blob )
' Create CryptoMessage object
Set Context = CM.OpenContext("mycontainer", True)
Set Msg = Context.CreateMessage
' Specify recipient certificate and send encrypted message
Msg.AddRecipientCert Cert
Mail.SendEncrypted Msg
Else
Response.Write "Certificate not found in the database."
End If
%>
<B>Message has been sent.</B>
</BODY>
</HTML>
This script uses two components at the same time, AspEmail and AspEncrypt. As before, we will review this code snippet in detail.
The block
Set Mail = Server.CreateObject("Persits.MailSender")
Mail.Host = "mail.yourcompanyshost.com"
Mail.From = "me@yourcompanyshost.com"
Mail.FromName = "On-line Sales" ‘ Optional
Mail.Subject = "Order Information."
Mail.Body = "Message body."
should be familiar to those who have used AspEmail, or any other mail component for that matter. Here we create an instance of the AspEmail object and specify standard parameters necessary to send an E-mail message: the address of a valid SMTP host used to send the message, the E-mail address, and (optionally) the name of the sender, and the subject and body of the message.
We have seen these lines in the previous snippet as well:
Set CM = Server.CreateObject("Persits.CryptoManager")
Set Blob = CM.CreateBlob
Here we create an instance of AspEncrypt’s CryptoManager object and create an empty blob object, which is to hold a certificate from the repository.
set rs = Server.CreateObject("adodb.recordset")
rs.Open "select email, cert from CERTS where id=1", _
"dsn=crypto;uID=sa;PWD=xxx;", 2, 3
To obtain a recipient’s E-mail address and certificate from our database repository, we use the ADO Recordset object. Here we attempt to retrieve the record with ID=1.
The next line (not shown here) is to make sure the SELECT statement yielded a result, otherwise an error message is displayed and the execution of the script is terminated.
The next line
Mail.AddAddress Trim(rs("email"))
passes the retrieved E-mail address (trimmed of trailing spaces) to AspEmail. If the message is to be sent to multiple recipients, you should call Mail.AddAddress (or AddCC/AddBcc, if appropriate) as many times as there are recipients.
The next two lines
Blob.Binary = rs("cert").Value
Set Cert = CM.ImportCertFromBlob( Blob )
import the certificate blob from the database record to a CryptoCert object (by means of a CryptoBlob object).
The next two lines:
Set Context = CM.OpenContext("mycontainer", True)
Set Msg = Context.CreateMessage
create an instance of the CryptoMessage object, which encapsulates S/MIME-compatible message signing and encryption functionality. We will be passing the CryptoMsg object to the AspEmail component shortly. To create a CryptoMessage object, we must first create an instance of the CryptoContext object that encapsulates a Cryptographic Context handle, a central notion in the Windows implementation of cryptography.
A Cryptographic Context is "something" that connects a key container (a section in the system registry that stores public/private key pairs for a certain user) with a cryptographic service provider (CSP), a DLL that contains the implementations of cryptographic algorithms. The OpenContext method requires two parameters: a key container name (it can be any string), and a Boolean flag specifying whether the key container is located in the HKEY_LOCAL_MACHINE (if set to True) or HKEY_CURRENT_USER (if set to False) section of the registry. It is recommended to set this flag to True if you are using AspEncrypt in the ASP environment, and False if you are using it from Visual Basic. For more information on cryptographic contexts, CSPs, etc., visit the AspEncrypt.com Web site.
The next line assigns the recipient certificate to the CryptoMessage object. If there are multiple recipients, you should call the AddRecipientCert method as many times as there are recipient certificates.
Msg.AddRecipientCert Cert
And finally, the encrypted message is sent with the line
Mail.SendEncrypted Msg
A Simplified Architecture without a Certificate Repository
If you only have one or two clients who need to receive encrypted mail, there is no need for a certificate repository described above. You can just store client certificates (without a private key) as files on the server’s hard drive. As a result you no longer need the certificate upload script described in section IV, and the message-sending code is significantly simplified. There is no need for a blob object anymore as we can import a certificate directly from a file using the ImportCertFromFile method. There is no need for an ADO Recordset either. The second half of our code will now look something like this:
<%
‘ set all Mail properties
Set CM = Server.CreateObject("Persits.CryptoManager")
Mail.AddAddress "jsmith@somecompany.com"
' Import certificate from file
Set Cert = CM.ImportCertFromFile( "c:\www\username\cert.cer" )
' Create CryptoMessage object
Set Context = CM.OpenContext("mycontainer", True)
Set Msg = Context.CreateMessage
' Specify recipient certificate and send encrypted message
Msg.AddRecipientCert Cert
Mail.SendEncrypted Msg
%>
The best way for you to obtain your client’s personal certificate is to ask them to send you a digitally signed E-mail. You will be able to extract his certificate straight from the E-mail message. This ensures that your client has installed his certificate properly in Outlook Express (or whatever E-mail application they are using), otherwise they wouldn’t be able to send you a signed message in the first place.
Figure 4
Another way of obtaining a certificate file is to export the certificate from the certificate store on the client’s machine. Internet Explorer 5.0 makes this task very easy: go to Tools/Internet Options, choose the Content tab and click on Certificates. The Certificate Manager application will pop up. Click on the certificate you want to export and click on Export. When asked the question "Do you want to export the private key with the certificate?" you must select No.
Instruct your client to follow this procedure and send you the exported certificate file with the extension .cer.
Strong Encryption
By default, AspEncrypt encrypts messages with a 40-bit RC2, variable key-length cipher, key. The RC2 key itself is encrypted using the certificate’s public key, which can be 512-bit or 1024-bit long. Instead of RC2, AspEncrypt can use the Triple Data Encryption Standard (DES) algorithm, which employs 168-bit keys (see Appendix). To enable this option, you must pass True as an argument to the CreateMessage method, as follows:
Set Msg = Context.CreateMessage( True )
To use strong encryption, both the server and client machines must have the Microsoft Enhanced Cryptographic Service Provider installed. The Enhanced CSP is installed automatically when you install the 128-bit security patch for IE available from http://www.microsoft.com/windows/ie/download/128bit/intro.htm. Note that strong encryption is currently available only in the U.S. and Canada.
Other Features and Where to Get More Help
AspEncrypt is also capable of sending digitally signed mail and messages that are first signed and then encrypted. Message signing guarantees data integrity and authenticity of the sender. Sending signed mail is a somewhat more complicated task since it involves a sender’s private key, and due to certain limitations of the Windows implementation of cryptography, not every private key can be used to sign mail in the ASP environment. This topic is beyond the scope of this article. However, it is described in detail on the AspEncrypt.com Web site, along with many other AspEncrypt-based cryptographic tasks, such as encrypting files, protecting password information, and issuing X.509 certificates.
If you have any questions, please direct them to info@aspencrypt.com
Useful Resources
- Schneier, Bruce. Applied Cryptography, 2nd, New York: John Wiley & Sons, 1996.
- S/MIME Reference: http://www.rsa.com/smime
- PKCS#7: http://www.rsasecurity.com/rsalabs/pkcs/
- AspEncrypt Web Site: http://www.aspencrypt.com
- AspEmail Web Site: http://www.aspemail.com
- Persits Software, Inc., Web Site: http://www.persits.com
About the Author
Peter Persits is the founder and president of Persits Software, Inc., the
vendor of the popular ASP components AspUpload, AspNTUser, AspGrid,
AspAccessControl, and AspEmail. He has been developing software for
Microsoft platforms for over ten years. Peter holds a Master's degree in
Computer Science from American University (Washington, DC), and is a
Microsoft Certified Solution Developer. Peter Persits currently lives in
Arlington, VA.
|