Security is important on the Web. Whether sharing financial, business, or personal information, people want to know with whom they are communicating (authentication), they want to ensure that what is sent is what is received (integrity), and they want to prevent others from intercepting what they are communicating (privacy). The Secure Sockets Layer protocol [13] provides one means for achieving these goals and is the subject of this article. We introduce SSL by reviewing cryptographic techniques and by discussing certificates. We then describe SSL and packages for implementing SSL. We conclude with examples of how to use SSLeay, the free implementation of SSL by Eric Young. We use the SSLeay toolkit to create a Certificate Authority, as well as server and client certificates.
There are two categories of cryptographic algorithms: conventional and public key.
A summary such as this is called a message digest, or one-way hash. Message digests are used to create short, fixed-length representations of longer, variable-length messages. Digest algorithms are designed to produce unique digests for different messages. Message digests are designed to make it too difficult to determine the message from the digest, and also impossible to find two different messages which create the same digest -- thus eliminating the possibility of substituting one message for another while maintaining the same digest.
Another challenge that Alice faces is finding a way to send the digest to the bank securely; when this is achieved, the integrity of the associated message is assured. One way to to this is to include the digest in a digital signature.
Digital signatures are created by encrypting a digest of the message, and other information (such as a sequence number) with the sender's private key. Though anyone may decrypt the signature using the public key, only the signer knows the private key. This means that only they may have signed it. Including the digest in the signature means the signature is only good for that message; it also ensures the integrity of the message since no one can change the digest and still sign it. To guard against interception and reuse of the signature by an intruder at a later date, the signature contains a unique sequence number. This protects the bank from a fraudulent claim from Alice that she did not send the message -- only she could have signed it (non-repudiation).
|
A distinguished name is used to provide an identity in a specific context -- for instance, an individual might have a personal certificate as well as one for their identity as an employee. Distinguished names are defined by the X.509 standard [2], which defines the fields, field names, and abbreviations used to refer to the fields (Table 2).
|
A Certificate Authority may define a policy specifying which distinguished field names are optional, and which are required. It may also place requirements upon the field contents, as may users of certificates. As an example, a Netscape browser requires that the Common Name for a certificate representing a server have a name which matches a regular expression for the domain name of that server, such as *.opengroup.org.
The binary format of a certificate is defined using the ASN.1 notation [ 1], [4]. This notation defines how to specify the contents, and encoding rules define how this information is translated into binary form. The binary encoding of the certificate is defined using Distinguished Encoding Rules (DER), which are based on the more general Basic Encoding Rules (BER). For those transmissions which cannot handle binary, the binary form may be translated into an ASCII form by using base64 encoding. This encoded version is called PEM encoded, when placed between the following lines:
-----BEGIN CERTIFICATE----- -----END CERTIFICATE-----
A number of companies, such as VeriSign [11] have established themselves as certificate authorities. These companies provide the following services:
It is also possible to create your own Certificate Authority. Although risky in the Internet environment, it may be useful within an Intranet where the organization can easily verify the identities of individuals and servers.
The protocol is designed to support a range of choices for specific algorithms used for cryptography, digests, and signatures. This allows algorithm selection for specific servers to be made based on legal, export or other concerns, and also enables the protocol to take advantage of new algorithms. Choices are negotiated between client and server at the start of establishing a protocol session.
There are a number of versions of the SSL protocol, as shown in Table 3.
| Version | Source | Description | Browser Support |
|---|---|---|---|
| SSL 2.0 | published by Netscape [12] | Original protocol | Netscape 3.0, Internet Explorer 3.0 |
| SSL 3.0 | Expired Internet Draft [13] | Revisions to prevent specific security attacks, add ciphers, and support certificate chains | Netscape 3.0, Internet Explorer 3.0 |
| TLS 2.0 | IETF Draft [15] | Revision of SSL 3.0 | None |
As noted in Table 3, one of the benefits in SSL 3.0 is that it adds support of certificate chain loading. This feature allows a server to pass a server certificate along with issuer certificates to the browser. Chain loading also permits the browser to validate the server certificate, even if Certificate Authority certificates are not installed for the intermediate issuers, since they are included in the certificate chain. SSL 3.0 is the basis for the Transaction Layer Security [TLS] protocol standard, currently in development by the Internet Engineering Task Force (IETF).
The elements of the handshake sequence, as used by the client and server, are listed below:
![]() |
The first step, Cipher Suite Negotiation, allows the client and server to choose a Cipher Suite supportable by both of them. The SSL3.0 protocol specification defines 31 Cipher Suites. A Cipher Suite is defined by the following components:
One variable in the choice of key exchange methods is digital signatures -- whether or not to use them, and if so, what kind of signatures to use. Signing with a private key provides assurance against a man-in-the-middle-attack during the information exchange used in generating the shared key [8, p516].
The message digest is used to create a Message Authentication Code (MAC) which is encrypted with the message to provide integrity and to prevent against replay attacks.
![]() |
The encapsulation of SSL control protocols by the record protocol means that if an active session is renegotiated the control protocols will be transmitted securely. If there were no session before, then the NULL cipher suite is used, which means there is no encryption and messages have no integrity digests until the session has been established.
![]() |
There are two prominent RSA public key packages available:
The RSA Reference implementation, an unsupported source code toolkit from RSA, may be used for freeware and non-commercial applications. Consensus Development Corp used to market a license for commercial use but will no longer do so [17].
Commercial implementation of RSARef[16].
Sample SSL 3.0 implementation from Netscape Communications Corporation [19].
Commercial source code toolkit available from Consensus Development Corp, an enhancement of SSLRef3.0. It requires BSAFE3.0 (from RSA) for use [20].
SSL3.0 compliant toolkit written in Java from Phaos Technology [18].
SSLeay-0.8.1 [21] is a free non-commercial implementation of SSL 2.0 and 3.0. It includes a public key implementation which may be used outside the United States. In the United States, RSARef or BSAFE3.0 must be used due to patent requirements. SSLeay offers an inexpensive way to get started with SSL, and is the subject of the next section.
Install the self-signed certificate in a browser so the browser will recognize server certificates signed by the Certificate Authority. Installing a CA certificate in a browser is somewhat dangerous, unless you trust that certificate and the security of the Certificate Authority. Once installed, the browser accepts any certificate signed by that authority.
To install the CA certificate, load it using HTTP Content-Type application/x-x509-ca-cert. To do this in a manner which does not depend on the server, use the cgi-script (Example 6 in the Appendix), or save the certificate in a file with a cacert suffix and define this suffix in the server configuration file to correspond to the application/x-x509-ca-cert MIME type. For the Apache server, for example, add the line AddType application/x-x509-ca-cert cacert to srm.conf. The certificate and key files must also remain available to SSLeay for the server to be able to use the public key, and the certificate authority to use the private key.
cp newcert.pem $certdir/sitecert.pem cp newkey.pem $certdir/sitekey.pem |
cd $certdir ln -s sitecert.pem `$SSLDIR/bin/x509 -noout -hash < sitecert.pem`.0 |
$SSLDIR/bin/x509 -in CAcert.pem -out CAcert.der -outform DER |
Once these steps have been completed, an SSL connection may be established if the server does not require client certificates.
Different clients such as Netscape Navigator 3.01 Gold and Microsoft Internet Explorer 3.02 support different mechanisms for creating client certificates. In this section, we demonstrate a technique for creating and installing a client certificate for each, using SSLeay certificate routines to sign certificate requests (Back up the Windows NT registry before creating client certificates with Internet Explorer).
The procedure for creating a client certificate involves HTML forms; these forms include client specific features such as special tags or JavaScript programs, and Perl CGI scripts that call SSLeay certificate handling applications. The procedures do not rely on special server features, other than the ability to run Perl CGI scripts. The examples completely automate the process, causing a client certificate to be installed once the request form is submitted. (In a production environment the Certificate Authority would need to perform validation instead of automatically issuing the certificate.)
The general steps for creating a client certificate are as follows:
The HTML form includes fields (containing defaults) for the different distinguished name attributes which are to be used in the client certificate, information allowing the browser to generate a key-pair, and a hidden field used to return this information to the CGI script. This hidden information is browser dependent.
In Netscape Navigator, the form contains an additional FORM tag, the <KEYGEN> tag. This tag creates a key pair, and causes the public key to be returned as a form value when the form is submitted (see Example 12 in the Appendix for source of a sample form). The <KEYGEN> tag causes the browser to display a choice of security grades, depending on the version of Navigator. All of the form information is used by the CGI script to create a certificate request, and this request is used to create a client certificate (See Figure 4).
|
The Microsoft Internet Explorer HTML form in Figure 5 is more complicated, because Internet Explorer requires a JavaScript (or Visual Basic) program in the page to use an ActiveX control to generate a key pair and create a certificate request. The JavaScript program is downloaded with the HTML page, and called when you press the Submit form button. The program calls the GenReqForm method of the certenr3 ActiveX control, passing it the distinguished name values from the form. The certificate request produced by the control is then loaded into a hidden field of the form, and returned with the form values to the server CGI script (see Example 15 in the Appendix for a sample HTML page).
|
Both Netscape Navigator and Microsoft Internet Explorer present a sequence of dialogs as part of the key-pair creation. If this sequence is sucessfully completed then the form will cause the server CGI script to be called with the data from the form. Examples 13 and 15 in the Appendix present two CGI scripts, one for each browser, since the processing is different.
The CGI script for Netscape Navigator (Example 14 in the Appendix) creates a file containing the distinguished name values returned by the form, and a special SPKAC value for the "Signed Public Key And Challenge" generated by Navigator The "ca" command is called with this file as an argument to generate a client certificate. If successful this is returned by the CGI script as an application/x-x509-user-cert HTTP Content-Type. Navigator recognizes this type, and prompts the user for the remainder of the steps required to install the user certificate in the browser. (See Example 13 for the sample CGI script for Netscape Navigator).
The CGI script for processing the Internet Explorer request (Example 16 in the Appendix) is more complicated. It takes the certificate request returned by the form and reformats it to conform to lines of length 72, and then uses the SSLeay ca command to create a signed user certificate based on this request. It then takes the client certificate and combines it with the SSLeay certificate revocation list (CRL) to create a PKCS#7 certificate using the SSLeay crl2pkcs7 utility. The CGI Perl script then dynamically creates an HTML page which includes a JavaScript program to call the AcceptCredentials method of the certenr3 ActiveX control to install the PKCS#7 certificate. This page is designed to take advantage of the JavaScript onLoad method to automatically call the JavaScript program when the page is loaded, so that the certificate is immediately installed without user interaction. (In a production system such automatic installation may not be desired.)
Once the HTML forms and CGI scripts have been written, and the ActiveX control installed, the process of creating client certificates using SSLeay is simple for users.
# Set SSLVerifyClient to: # 0 if no certicate is required # 1 if the client may present a valid certificate # 2 if the client must present a valid certificate # 3 if the client may present a valid certificate but it is not required to # have a valid CA SSLVerifyClient 0 |
The following examples assume you are working in the SSLeay-0.8.1 directory. Change to this directory and build SSLeay following the directions in the INSTALL file. The examples assume that the results of building SSLeay are installed in $SSLDIR (e.g. /opt/dev/ssl).
SSLeay uses a configuration file (ssleay.cnf) which supports named sections, so one configuration file may be used for several purposes. We have modified this file, and show some of these modifications in the examples that follow. Subsequent descriptions in this document show various relevant sections of the log file.
Note that the addition of SSL to the server requires rebuilding the server to include the SSL toolkit and public key sources, and modifying the server configuration to support SSL.
mkdir ${SSLDIR}/certs
mkdir ${SSLDIR}/crl
mkdir ${SSLDIR}/newcerts
mkdir ${SSLDIR}/private
echo "01" > ${SSLDIR}/serial
touch ${SSLDIR}/index.txt
|
#################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = /opt/dev/ssl # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/private/CAcert.pem # The CA certificate serial = $dir/serial # The current serial number crl = $dir/clr/crl.pem # The current CRL private_key = $dir/private/CAkey.pem # The private key RANDFILE = $dir/private/.rand # private random number file x509_extensions = x509v3_extensions # The extentions to add to the cert default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = md5 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match |
The "req" section of the configuration file is used when creating certificate requests, and supplies defaults and length limits for the various distinguished name fields. In our examples it has the configuration as shown in Example 3.
[ req ] default_bits = 512 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = US countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = MA localityName = Locality Name (eg, city) localityName_default = Cambridge organizationName = Organization Name (eg, company) organizationName_default = The Open Group organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = Research Institute commonName = Common Name (eg, YOUR name) commonName_default = example.osf.org commonName_max = 64 emailAddress = Email Address emailAddress_max = 40 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 |
The policy section of the configuration file is used to define different certificate request signing policies. The examples here include the most lenient policy (policy_anything) and a stricter policy (policy_match) which restricts the values of certificate fields. The purpose of a policy is to guide processing of a certificate request.
In Example 4, match means that the value of the field in the request must match the value in the CA certificate, or the request will not be signed. optional means the the field need not be present, while supplied means that it must be present in the certificate request.
# For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = match commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional |
$SSLDIR/bin/ssleay req -new -x509 -keyout ${SSLDIR}/private/CAkey.pem \
-out ${SSLDIR}/private/CAcert.pem -config /opt/www/lib/ssleay.cnf
Using configuration from /opt/www/lib/ssleay.cnf
Generating a 512 bit private key
writing new private key to '../private/CAkey.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorperated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [MA]:
Locality Name (eg, city) [Cambridge]:
Organization Name (eg, company) [The Open Group]:
Organizational Unit Name (eg, section) [Research Institute]:
Common Name (eg, YOUR name) [example.osf.org]:Example CA
Email Address []:f.hirsch@opengroup.org
|
The SSLeay configuration file specifies the location of the CA certificate and key files using the following directives in the ca section:
# The CA certificate certificate = $dir/private/CAcert.pem # The private key private_key = $dir/private/CAkey.pem |
The Apache-SSL server httpd.conf file specifies the CA certificate and key files as follows:
# Set the CA certificate verification path (must be PEM encoded). SSLCACertificatePath /opt/dev/ssl/private # Set the CA certificate verification file (must be PEM encoded). SSLCACertificateFile /opt/dev/ssl/private/CAcert.pem |
<HTML><HEAD><TITLE>Load CA Certificate</TITLE></HEAD><BODY> <H1>Load Certificate Authority Certificate</H1> <FORM ACTION="http://example.osf.org/cgi-bin/loadCAcert.pl" METHOD=post> <TABLE> <TR> <TD>Netscape Browser (PEM Format):</TD> <TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="PEM" CHECKED></TD></TR> <TR><TD>Microsoft Browser (DER Format):</TD> <TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="DER"></TD></TR> </TABLE> <INPUT TYPE="SUBMIT" VALUE="Load Certificate"> </FORM> </BODY></HTML> |
Example 7 shows the loadCAcert.pl script.
#!/usr/local/bin/perl -T
require 5.003;
use strict;
use CGI;
my $cert_dir = "/opt/www/lib/certs";
my $cert_file = "CAcert.pem";
my $query = new CGI;
my $kind = $query->param('FORMAT');
if($kind eq 'DER') { $cert_file = "CAcert.der"; }
my $cert_path = "$cert_dir/$cert_file";
open(CERT, "<$cert_path");
my $data = join '', |
Install the Certificate Authority certificate in the server certificate database as well as the browser, so that the server is able to locate the public key and validate certificate signatures signed by the certificate authority.
cd $SSLDIR/bin ./ssleay req -new -keyout newkey.pem -out newreq.pem -days 360\ -config /opt/www/lib/ssleay.cnf Using configuration from /opt/www/lib/ssleay.cnf Generating a 512 bit private key writing new private key to 'newkey.pem' Enter PEM pass phrase: Verifying password - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorperated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [US]: State or Province Name (full name) [MA]: Locality Name (eg, city) [Cambridge]: Organization Name (eg, company) [The Open Group]: Organizational Unit Name (eg, section) [Research Institute]: Common Name (eg, YOUR name) [example.osf.org]: Email Address []:f.hirsch@opengroup.org Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: |
Example 9 shows the results in a certificate request being created in newreq.pem (in this paper certificates and keys are truncated).
-----BEGIN CERTIFICATE REQUEST----- MIIBXTCCAQcCAQAwgaMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTESMBAGA1UE ... Aty7AlcmN9XNwxUk1w0H3hk= -----END CERTIFICATE REQUEST----- |
Example 10 shows a private key for the certificate being created in newkey.pem.
-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,21F13B37A796482C XIY0c7gnv0BpVKkOqXIiqpyONx8xqW67wghzDlKyoOZt9NDcl9wF9jnddODwv9ZU ... QxS2zwfKG1u+YqS1c2v5ecBgqW78DQLvxMkpYU8+xge7vDeoYKE14w== -----END RSA PRIVATE KEY----- |
When this command is executed, it prompts for the certificate authority password, as shown in Example 11.
cat newreq.pem newkey.pem > new.pem ./ssleay ca -policy policy_anything -out newcert.pem \ -config /opt/www/lib/ssleay.cnf -infiles new.pem Using configuration from /opt/www/lib/ssleay.cnf Enter PEM pass phrase: Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'MA' localityName :PRINTABLE:'Cambridge' organizationName :PRINTABLE:'The Open Group' organizationalUnitName:PRINTABLE:'Research Institute' commonName :PRINTABLE:'example.osf.org' emailAddress :IA5STRING:'f.hirsch@opengroup.org' Certificate is to be certified until May 12 15:39:33 1998 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated |
The server certificate is created in the file newcert.pem as shown in Example 12 (line-breaks added for issuer and subject).
issuer :/C=US/SP=MA/L=Cambridge/O=The Open Group/OU=Research Institute/
CN=Example CA/Email=f.hirsch@opengroup.org
subject:/C=US/SP=MA/L=Cambridge/O=The Open Group/OU=Research Institute/
CN=example.osf.org/Email=f.hirsch@opengroup.org
serial :01
Certificate:
Data:
Version: 0 (0x0)
Serial Number: 1 (0x1)
Signature Algorithm: md5withRSAEncryption
Issuer: C=US, SP=MA, L=Cambridge, O=The Open Group,
OU=Research Institute,
CN=Example CA/Email=f.hirsch@opengroup.org
Validity
Not Before: May 12 15:39:33 1997 GMT
Not After : May 12 15:39:33 1998 GMT
Subject: C=US, SP=MA, L=Cambridge, O=The Open Group,
OU=Research Institute,
CN=example.osf.org/Email=f.hirsch@opengroup.org
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Modulus:
00:a1:41:0b:0c:15:53:a5:a5:c4:37:a8:48:f5:79:
39:9f:18:2d:f4:bf:43:34:36:21:23:03:48:a5:65:
cb:e2:f8:97:af:9c:7d:df:1e:9b:54:e2:ad:21:e3:
41:3e:54:9a:ce:dc:66:4d:61:59:fb:83:11:36:bf:
9c:3b:47:20:fb
Exponent: 65537 (0x10001)
Signature Algorithm: md5withRSAEncryption
63:77:e7:f8:aa:0b:90:5e:13:9e:4b:57:f1:0f:22:f9:4c:e3:
7a:aa:ff:a7:8a:2e:3c:1c:a2:92:07:bc:9f:22:3f:2f:13:3f:
60:62:57:a7:74:12:35:28:82:b1:00:2a:36:54:de:67:cd:a2:
9e:24:3e:98:be:14:4e:35:b7:7f
-----BEGIN CERTIFICATE-----
MIICLTCCAdcCAQEwDQYJKoZIhvcNAQEEBQAwgZ4xCzAJBgNVBAYTAlVTMQswCQYD
...
Ij8vEz9gYlendBI1KIKxACo2VN5nzaKeJD6YvhRONbd/
-----END CERTIFICATE-----
|
The Apache-SSL httpd.conf file must be modified to specify the server certificate and key files as follows:
# Point SSLCertificateFile at a PEM encoded certificate. SSLCertificateFile /opt/www/lib/certs/sitecert.pem # If the key is not combined with the certificate, use this directive to # point at the key file. If this starts with a '/' it specifies an absolute # path, otherwise it is relative to the default certificate area. That is, # it means "/private/". SSLCertificateKeyFile /opt/www/lib/certs/sitekey.pem |
<HTML><HEAD><TITLE>Create Client Certificate</TITLE></HEAD><BODY> <CENTER><H1>Create Client Certificate</H1></CENTER> <FORM NAME="GenerateForm" ACTION="http://example.osf.org/cgi-bin/ns_key.pl"> <TABLE> <TR><TD>Common Name:</TD><TD> <INPUT TYPE="TEXT" NAME="commonName" VALUE="Client Certificate" SIZE=64> </TD></TR> <TR><TD>email:</TD><TD> <INPUT TYPE="TEXT" NAME="emailAddress" VALUE="f.hirsch@opengroup.org" SIZE=40> </TD></TR> <TR><TD>Organization:</TD><TD> <INPUT TYPE="TEXT" NAME="organizationName" VALUE="The Open Group"> </TD></TR> <TR><TD>Organizational Unit:</TD><TD> <INPUT TYPE="TEXT" NAME="organizationalUnitName" VALUE="Research Institute"> </TD></TR> <TR><TD>Locality (City):</TD><TD> <INPUT TYPE="TEXT" NAME="localityName" VALUE="Cambridge"> </TD></TR> <TR><TD>State:</TD><TD> <INPUT TYPE="TEXT" NAME="stateOrProvinceName" VALUE="MA"> </TD></TR> <TR><TD>Country:</TD><TD> <INPUT TYPE="TEXT" NAME="countryName" VALUE="US" SIZE="2"> </TD></TR> </TABLE> <!-- ' keygen is Netscape specific and will be ignored in ' internet explorer --> <KEYGEN NAME="SPKAC" CHALLENGE="challengePassword"> <INPUT TYPE="SUBMIT" NAME="SUBMIT"> </FORM> <P><HR></BODY></HTML> |
#!/usr/local/bin/perl
require 5.003;
use strict;
use CGI;
use File::CounterFile; # module to maintain certificate request counter
my $doc_dir = $ENV{'DOCUMENT_ROOT'}; # apache specific location for storage
unless($doc_dir) {
print "<HTML><HEAD><TITLE>Failure</TITLE></HEAD>";
print "<BODY>DOCUMENT_ROOT not defined</BODY></HTML>";
exit(0);
}
my $base_dir = $doc_dir;
$base_dir =~ s/\/htdocs//;
my $SSLDIR = '/opt/dev/ssl'; # define where SSLeay files are located
my $CA = "$SSLDIR/bin/ca";
my $CONFIG = "/opt/www/lib/ssleay.cnf";
my $CAPASS = "caKEY";
my $query = new CGI; # get a handle on the form data
my $key = $query->param('SPKAC'); # this will fail if not Netscape browser
unless($key) { fail("No Key provided $key. Netscape required"); }
my $counter = new File::CounterFile("$base_dir/.counter", 1);
unless($counter) { fail("Could not create counter: $!"); }
my $count = $counter->inc();
my $certs_dir = "$base_dir/certs";
my $req_file = "$certs_dir/cert$count.req"; # certificate request filename
my $result_file = "$certs_dir/cert$count.result"; # certificate filename
# Explicitly list form fields we must have for certificate creation to work.
my @req_names = ('commonName', 'emailAddress', 'organizationName',
'organizationalUnitName', 'localityName', 'stateOrProvinceName',
'countryName', 'SPKAC');
# build the request file
open(REQ, ">$req_file") or fail("Could not create request $req_file: $!");
my $name;
foreach $name (@req_names) {
my $value = $query->param("$name");
$value =~ tr/\n//d;
print REQ "$name = $value\n";
}
close(REQ);
# make sure we actually created a request file
unless(-f $req_file) { fail("request missing: $req_file"); }
unless(-e $CA) { fail("command missing"); } # ensure that ca command will run
# command for processing certificate request, without password
my $cmd = "$CA -config $CONFIG -spkac $req_file -out $result_file -days 360";
my $rc = system("$cmd -key $CAPASS 2>errs");
if($rc != 0) { fail("$cmd<P>rc = $rc", "errs"); }
open(CERT, "<$result_file") or fail("Could not open $result_file<P>$!");
# send the client certificate to the browser
print "Content-Type: application/x-x509-user-cert\n";
my $result = join '', <CERT>;
close CERT;
my $len = length($result);
print "Content-Length: $len\n\n";
print $result;
exit(0);
sub fail {
my($msg, $errs) = @_;
print $query->header;
print $query->start_html(-title => "Certificate Request Failure");
print "<H2>Certificate request failed</H2>$msg<P>";
if($errs) {
if(open(ERR, "<errs")) {
while(<ERR>) {
print "$_<BR>";
}
close ERR;
}
}
print $query->dump();
print $query->end_html();
exit(0);
}
1;
|