This document explains the step by step procedure in configuring SSL based apache server (https) which servers subversion repositories and authenticates the clients using a PKCS#12 (http://www.rsa.com/rsalabs/node.asp?id=2138) based certificate provided by the client, when challenged by the server.
- apache 2.0 or greater
- openssl 0.9 or greater
./configure --prefix=/usr/local/httpd-2.2.9 --enable-ssl --enable-dav=shared --enable-dav-fs=shared --enable-dav-lock=shared --enable-rewrite=shared
Edit the following parameters in openssl.cnf file, this will help in adding some default values, when you are prompted.
#################################################################### [ ca ] default_ca = ServerCA # The default ca section #################################################################### [ ServerCA ] dir = /opt/ssl/ServerCA # 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. #unique_subject = no # Set to 'no' to allow creation of # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/CA/ServerCA.crt # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/CA/ServerCA.crl # The current CRL private_key = $dir/CA/ServerCA.key # The private key RANDFILE = /var/run/prngd-socket # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options ... ... [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = IN countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = TamilNadu localityName = Locality Name (eg, city) localityName_default = Chennai 0.organizationName = Organization Name (eg, company) 0.organizationName_default = My organization # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = Subversion commonName = Common Name (eg, YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_default = mymail@example.com emailAddress_max = 64 # SET-ex3 = SET extension number 3 ...
These are the directories which we ll use as sandbox to hold our certificates, keys, requests, etc.
$ mkdir -p /opt/ssl/ServerCA/CA $ mkdir -p /opt/ssl/ServerCA/newcerts $ mkdir -p /opt/ssl/ServerCA/server/certs $ mkdir -p /opt/ssl/ServerCA/server/requests $ mkdir -p /opt/ssl/ServerCA/server/keys $ mkdir -p /opt/ssl/ServerCA/user/certs $ mkdir -p /opt/ssl/ServerCA/user/requests $ mkdir -p /opt/ssl/ServerCA/user/keys $ echo "01" > /opt/ssl/ServerCA/serial $ touch /opt/ssl/ServerCA/index.txt
Create the CA key for the root certificate,
$ openssl genrsa -out /opt/ssl/ServerCA/CA/ServerCA.key 1024 Generating RSA private key, 1024 bit long modulus ......++++++ ...............++++++ e is 65537 (0x10001)
Create CA cert request for root certificate,
$ openssl req -new -key /opt/ssl/ServerCA/CA/ServerCA.key -out \ /opt/ssl/ServerCA/CA/ServerCA.csr You are about to be asked to enter information that will be incorporated 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) [IN]: State or Province Name (full name) [TamilNadu]: Locality Name (eg, city) [Chennai]: Organization Name (eg, company) [My organization]: Organizational Unit Name (eg, section) [Subversion]: Common Name (eg, YOUR name) []:Senthil Kumaran S Email Address [mymail@example.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:simple An optional company name []:
Self sign the CA certificate,
$ openssl x509 -req -days 365 -in /opt/ssl/ServerCA/CA/ServerCA.csr -out \ /opt/ssl/ServerCA/CA/ServerCA.crt -signkey /opt/ssl/ServerCA/CA/ServerCA.key Signature ok subject=/C=IN/ST=TamilNadu/L=Chennai/O=My organization/OU=Subversion/CN=Senthil Kumaran S/emailAddress=mymail@example.com Getting Private key
Create a key for the web server certificate,
openssl genrsa -des3 -out /opt/ssl/ServerCA/server/keys/serverWEB.key 1024 Generating RSA private key, 1024 bit long modulus ..............++++++ ................................................++++++ e is 65537 (0x10001) Enter pass phrase for /opt/ssl/ServerCA/server/keys/serverWEB.key: Verifying - Enter pass phrase for /opt/ssl/ServerCA/server/keys/serverWEB.key:
Create web server certificate request,
$ openssl req -new -key /opt/ssl/ServerCA/server/keys/serverWEB.key -out \ /opt/ssl/ServerCA/server/requests/serverWEB.csr Enter pass phrase for /opt/ssl/ServerCA/server/keys/serverWEB.key: You are about to be asked to enter information that will be incorporated 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) [IN]: State or Province Name (full name) [TamilNadu]: Locality Name (eg, city) [Chennai]: Organization Name (eg, company) [My organization]: Organizational Unit Name (eg, section) [Subversion]: Common Name (eg, YOUR name) []:Senthil Kumaran S Email Address [mymail@example.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Sign web server cert with CA key,
$ openssl ca -days 365 -in /opt/ssl/ServerCA/server/requests/serverWEB.csr \
-cert /opt/ssl/ServerCA/CA/ServerCA.crt -keyfile /opt/ssl/ServerCA \
/CA/ServerCA.key -out /opt/ssl/ServerCA/server/certs/serverWEB.crt
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Jul 10 11:36:24 2008 GMT
Not After : Jul 10 11:36:24 2009 GMT
Subject:
countryName = IN
stateOrProvinceName = TamilNadu
organizationName = My organization
organizationalUnitName = Subversion
commonName = Senthil Kumaran S
emailAddress = mymail@example.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
C3:F7:B3:1F:54:7B:EC:B0:A4:49:A7:65:06:87:73:31:87:95:E5:6E
X509v3 Authority Key Identifier:
DirName:/C=IN/ST=TamilNadu/L=Chennai/O=My organization/OU=Subversion/CN=Senthil Kumaran S/emailAddress=mymail@example.com
serial:BF:73:AC:03:5A:18:E2:E2
Certificate is to be certified until Jul 10 11:36:24 2009 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
Put the following in your apache virtual host configuration:
NameVirtualHost *:443
<VirtualHost *:443>
ServerAdmin webmaster@localhost
ServerName localhost
DocumentRoot /var/www/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Location /svn/repos>
DAV svn
SVNPath /path/to/repos
<IfDefine SSL>
SSLRequireSSL
SSLRequire %{SSL_CLIENT_S_DN_O} eq "My Organization"
</IfDefine>
</Location>
ServerSignature On
SSLEngine on
SSLCertificateFile /opt/ssl/ServerCA/server/certs/serverWEB.crt
SSLCertificateKeyFile /opt/ssl/ServerCA/server/keys/serverWEB.key
SSLCACertificateFile /opt/ssl/ServerCA/CA/ServerCA.crt
SSLVerifyClient optional
SSLVerifyDepth 2
</VirtualHost>
Restart apache web server.
Apache/2.2.9 mod_ssl/2.2.9 (Pass Phrase Dialog) Some of your private key files are encrypted for security reasons. In order to read them you have to provide the pass phrases. Server localhost:443 (RSA) Enter pass phrase: OK: Pass Phrase Dialog successful.
Create user key,
$ openssl genrsa -des3 -out /opt/ssl/ServerCA/user/keys/user.key 1024 Generating RSA private key, 1024 bit long modulus .....................++++++ ................................................++++++ e is 65537 (0x10001) Enter pass phrase for /opt/ssl/ServerCA/user/keys/user.key: Verifying - Enter pass phrase for /opt/ssl/ServerCA/user/keys/user.key:
Create user cert request,
$ openssl req -new -key /opt/ssl/ServerCA/user/keys/user.key -out \ /opt/ssl/ServerCA/user/requests/user.csr Enter pass phrase for /opt/ssl/ServerCA/user/keys/user.key: You are about to be asked to enter information that will be incorporated 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) [IN]: State or Province Name (full name) [TamilNadu]: Locality Name (eg, city) [Chennai]: Organization Name (eg, company) [My organization]: Organizational Unit Name (eg, section) [Subversion]: Common Name (eg, YOUR name) []:Senthil Kumaran S Email Address [mymail@example.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Sign the user certificate request,
$ openssl ca -in /opt/ssl/ServerCA/user/requests/user.csr -cert \
/opt/ssl/ServerCA/CA/ServerCA.crt -keyfile /opt/ssl/ServerCA/CA/ServerCA.key \
-out /opt/ssl/ServerCA/user/certs/user.crt
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 2 (0x2)
Validity
Not Before: Jul 10 11:46:27 2008 GMT
Not After : Jul 10 11:46:27 2009 GMT
Subject:
countryName = IN
stateOrProvinceName = TamilNadu
organizationName = My organization
organizationalUnitName = Subversion
commonName = Senthil Kumaran S
emailAddress = mymail@example.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
BA:DA:1D:41:35:CF:45:86:56:26:7C:F3:5B:5B:7E:CA:72:C8:FB:D2
X509v3 Authority Key Identifier:
DirName:/C=IN/ST=TamilNadu/L=Chennai/O=My organization/OU=Subversion/CN=Senthil Kumaran S/emailAddress=mymail@example.com
serial:BF:73:AC:03:5A:18:E2:E2
Certificate is to be certified until Jul 10 11:46:27 2009 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
$ openssl pkcs12 -export -clcerts -in /opt/ssl/ServerCA/user/certs/user.crt \ -inkey /opt/ssl/ServerCA/user/keys/user.key -out /home/stylesen/user.p12 Enter pass phrase for /opt/ssl/ServerCA/user/keys/user.key: Enter Export Password: Verifying - Enter Export Password:
A sample run of accessing your subversion repository configured to accept client certificate for authentication would look like the following with current subversion trunk (r31507) code:
$ svn co https://localhost/svn/repos wc Authentication realm: https://localhost:443 Client certificate filename: /home/stylesen/user.p12 Passphrase for '/home/stylesen/user.p12': Checked out revision 0.
I have the following in my openssl.cnf
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha1 # 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 # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional
The above was a part of default openssl.cnf provided in Debian etch, hence I didn't made a note of it here and as Karl pointed out it went as a part of the "..." material.
I checked the openssl.cnf in Debian lenny package (http://packages.debian.org/lenny/openssl) which also had the same contents.
Karl, Thanks for noting it here which will help someone who gets the same error :)
When you run the command given above to sign the web server cert with the CA key...
openssl ca -days 365 -in \
/usr/local/ssl/CollabCA/server/requests/serverWEB.csr -cert \
/usr/local/ssl/CollabCA/CollabCA.crt -keyfile \
/usr/local/ssl/CollabCA/CollabCA.key -out \
/usr/local/ssl/CollabCA/server/certs/serverWEB.crt -config /etc/ssl/openssl.cnf
...you might encounter an error like this:
Using configuration from /etc/ssl/openssl.cnf
variable lookup failed for CollabCA::default_md
28082:error:02001002:system library:fopen:No such file or directory:\
bss_file.c:122:fopen('/usr/local/ssl/CollabCA/index.txt.attr','rb')
28082:error:2006D080:BIO routines:BIO_new_file:no such file:\
bss_file.c:125:
28082:error:0E078072:configuration file routines:DEF_LOAD:no such file:\
conf_def.c:197:
28082:error:0E06D06C:configuration file routines:NCONF_get_string:\
no value:conf_lib.c:329:group=CollabCA name=default_md
Note that the error might be about some other variable besides "default_md" (for example, once I solved the "default_md" problem, I got the same error about the "policy" variable).
The solution is to add new variables to /etc/ssl/openssl.cnf in the [CollabCA] section (substitute whatever name you used for your cert, of course):
[CollabCA]
...
default_md = sha1 # You could also use "md5" instead of "sha1".
policy = policy_match # I don't know what other policies are available.
...
The reason these errors didn't happen for stylesen is probably that he already had those variables set in the relevant section (they're part of the "..." material in his example).
I found this solution by doing...
search://"No such file or directory" bss_file.c index.txt.attr/
...which turned up this web page:
http://www.onlamp.com/pub/a/security/2004/10/21/vpns_and_pki.html?page=last