Creating a Certificate Authority using OpenSSL
© 2009-2014 Dennis Leeuw
Although this document is written as generic as possible it is highly influenced by the way cao works. See the Certificate Authority Operator script for more about cao.
All communication through the Internet is per definition unsafe since data traffels across unknown networks, and you will never know if someone on those unsafe networks is eavesdropping on your data, trying to change your data or even trying to redirect your data to another destination then you intended.
Due to these security implications we need some way to make sure non of the above will be happening and if it happens we will be able to tell that it has happened.
SSL or Secure Socket Layer was originally developed by Netscape, the IETF standard based on SSL is called TLS or Transport Layer Security. SSL version 3 incorporates TLS version 1. So one might say the SSL v3 is equal to TLS v1.
A term that you also might come across is Public Key Infrastructure (PKI). A PKI is the total of certificates, software and database that enables you to sign and revoke certificates, and distributes public keys.
As the name TLS already implies we are dealing with transport layer security. Both SSL and TLS live on top of TCP/IP and below the application layer:
http | ldap | imap | smtp | ... |
SSL / TLS | ||||
TCP/IP |
protocol | non-secure | secure |
---|---|---|
http | 80 | 443 |
ldap | 389 | 636 |
imap | 143 | 993 |
smtp | 25 | 465 |
To detect if someone has changed our data during transport we use a Message Authentication Code. Sometimes called a message digest.
From the data to be exchanged we calculate a number that is unique for the transmitted data. Of course it should not be possible to deduce the data from the number and changing anything in the data should give another message code.
With this extra number attached to our data the receiver can, by using the same algorithm, caculate a number from the received data and compare that with the received one, if they are identical then our data is not tampered with.
The OpenSSL configuration file openssl.cnf defines the algorithm in the default_md (message digest) parameter.
To get a feel for what a message digests looks like use the following commands on the command line:
echo test | openssl dgst -md5 echo test | openssl dgst -sha1Changing a single character in the string we echo should change the outcome of the command. For fun try the following:
echo -n test | openssl dgst -md5You will note that even removing the newline will dramastically change the output.
To make sure nobody can read your data you should encrypt it. This is the oldest form of security for any form of "written" data. For encyption and decryption you need an agreement between sender and receiver, the sender needs to know how to crypt the data and the receiver how to decrypt it. This agreement is called a cryptographic algorithm or a cipher. The problem with modern systems is that the cryptographic algorithems are known, so only using the cipher will not make your data safe. Instead a key is used in combination with the cipher. So we have a known cipher with an secret (unknown) key which encrypts your data and makes it safe.
With modern computers it is possible to recalculate the key used in the cipher. The longer and more difficult the key the harder it is (the more time is needed) to regenerate the key. Also some ciphers are more easy then others. All your security is related to the computing power available and the amount of time that is needed to regenerate your key. This is also related to the amount of time that data is valid. Meaning that if keys are used for a session of 8 hours and with the current technology it takes 12 hours to crack the key, you are safe, however if it only takes 2 hours, there are 6 hours left for an attacker to monitor your data.
Conclusion you have to use a strong enough algorithm (cipher), and a long enough key. Which brings us to the problem how systems that want to communicate with one another know which key to use.
The easiest way to use encryption is by using a symmetric-key, meaning that both sender and receiver use the same key. It is important to keep the key secret and only known to the intended users. You can generate a key, put it on an USB-stick and give it to a friend. If you both use that key to encrypt the data that you exchange, and both also use that key to decrypt the data, you are fine. This is what is called Symmetrich-key Encryption. An identical key is used at both ends.
A more complex situation arises, when there is no prior knowledge. System A has no key to encrypt data with that can be understood by system B. In this case one needs some sort of protocol that can be spoken by the two systems to exchange enough information so both agree on the to be used key. During this conversation someone overhearing the conversation should not be able to find the key. This sounds like rocket sience to you? Well, it more or less is, but it is possible. The most well known solution to the problem is the Diffie-Hellman key exchange.
Based on the description found on the OpenSSL website, we assume an Alice and a Bob that want to communicate to one another and there is an Eve that is eavesdropping on the communication. Let us assume that Alice starts out with a large prime number p and a generator g, using the OpenSSL tools this looks like this:
openssl genpkey -genparam -algorithm DH -out dhp.pemTo see what is generated use:
openssl pkeyparam -in dhp.pem -textWhich shows a large prime number and a short generator number.
Alice now sends this information to Bob, which Eve overhears and thus also receives.
Bob and Alice now both create a secret private key out of the blue using some randomness. Let us say that Alice her key is a and Bob his key is b. Both keep their key secret and thus Eve doesn't know about this.
Alice now calculates ga mod p and Bob calculates gb mod p, the outcome we will call their public keys.
openssl genpkey -paramfile dhp.pem -out dhkey-alice.pem openssl genpkey -paramfile dhp.pem -out dhkey-bob.pemYou can view both generated keys with (replace alice with bob to view Bobs keys):
openssl pkey -in dhkey-alice.pem -text -nooutAs you can see there is the private key, and the public key. The outcome of the modulo function is very hard to reverse. So knowing p and g and the outcome of the module function, lets call them A and B, makes it very hard to deduce a or b, this is known as the discrete logarithm problem. Based on this fact Alice and Bob send each other their public keys.
openssl pkey -in dhkey-alice.pem -pubout -out dhpub-alice.pem openssl pkey -in dhkey-bob.pem -pubout -out dhpub-bob.pemEve listening on the line reads the public keys:
openssl pkey -pubin -in dhpub-bob.pem -textWith as an result that Eve now knows p, g, A and B, but it can not recalculate a and b.
The final step is for Alice to calculate Ba and Bob calculates Ab, which give an identical outcome.
openssl pkeyutl -derive -inkey dhkey-alice.pem -peerkey dhpub-bob.pem -out shared-secret-alice.bin openssl pkeyutl -derive -inkey dhkey-bob.pem -peerkey dhpub-alice.pem -out shared-secret-bob.binAnd thus both now have a key that they can use to exchange data with, without Eve ever knowing what the key is. To prove that both shared secrets are identical use:
cmp shared-secret-alice.bin shared-secret-bob.bin
With public-key encryption there are two keys: a public and a private key. Data encrypted with the public key can only be decrypted with the private key. Data encrypted with the private key can only be decrypted with the public key. This means that everybody with the public key can read data encrypted with the private key, but only the one with the private key can decrypt data encrypted with the public key.
Public-key encryption is more processor intensive, however by using public-key encryption one can exchange symmetric keys in a secure way. This is how SSL works.
The most often used encryption key algorithm is called RSA. To generate a RSA private key use:
openssl genrsa -des3 -out key.pem 1024Where -des3 tells openssl to encrypt the private key with Triple-DES. This means a passphrase is asked as input for the Triple-DES encryption. The 1024 is the length of the encryption key, in this case 1024 bits. Guard this private key with your life, so set the owner ship accordingly:
chmod 0400 key.pem
To create the public counter part we use:
openssl rsa -in key.pem -pubout -out pub-key.pemWith cat you can view the contents of the files.
The generation of private keys, prime numbers and generator numbers should not be predictable otherwise the execution of openssl on one machine would result in the same numbers when run on another machine, which would make the entire exercise useless. The numbers should all be random.
How do you create randomness out of computers that are built to be predictable? They key is to generate entropy, uncertainty. This uncertainty can use time, the amount of keystrokes, the directions of the mouse movements, etc. in equations to generate random numbers. All human interaction on a computer is more or less unpredictable and can be used to create random numbers.
The Linux kernel provides you with an interface to watch the amount of entropy on the system:
/proc/sys/kernel/random/entropy_avail
To make your random numbers more random, generate them on a system that has a lot of entropy, do not create them on a server without mouse and keyboard that only runs a single service that is hardly used. Those system do not have a lot of entropy. A solution for creating more entropy on systems is provided by the rngd tool.
A digital signature is a prove of authenticity and has nothing to do with sending secure data. It only makes sure that the data that is received is not tampered with and came from the sending party. The process is quite easy to understand.
The sender generates a hash from the data that it wants to send. This hash is encrypted with the private key. The encrypted data together with some other information like the hashing algortithm is called a digital signature. The digital signature is sent to the receiving party together with the original data.
The receiving party decrypts the digital signature with the public key and extracts the hash. With the same hashing algorithm as the sender it creates a hash from the original data. If both hashes match one knows for sure that the data is not tampered with and that it came from the person from which we have the public key.
As long as the private key is not compromised we can be sure the data came from the right source and that the data is the original.
But that is the only thing we know! How do we know that the public key we have belongs to the person we want to talk to? Anybody can create a public and private key pair and tell us that the private key is from the president of the United States and we used the public key to decrypt his message, but are we certain that the message we got really came from the president of the United States?
How do we know that the public key is authentic?
In everyday life I use my passport to identify myself. However the process behind it assumes that my passport can identify me. When I apply for a passport they need a photograph (or actually two here in the Netherlands) and some additional information. This information is verified with all kinds of buraucratic instances to make sure that I am who I claim to be. Then my passport gets generated. With that passport I can identify myself with actually not more then the picture on the passport. Someone that wants to establish my identity compares the picture on the passport with my face and if there are enough similarities it can read my name and some other stuff and verify that with me. If I give the right answers it is assumed that I am me.
To do the same in an electronic fashion we need certificates. The authority that gives out certificates is called a Certificate Authority (CA). The CA is thus responsible for the checking of the credentials of the instance applying for a certificate.
The CA binds the certificate to the public key of the requesting party. With the certificate and the public key one can be sure that the data received is indeed encrypted with the private key of the instance.
A certificate should of course always include the public key, to make comparison possible, but it also includes the name of the entity it identifies (the Common Name), an expiration date, the name of the CA, a serial number, and next to some other information the digital signature of the CA.
This means that if you trust the CA, you can use the digital signature of the CA to verify that the received certificate is not tampered with. Meaning that the received public key in the certificate is the original. And with this original public key one can verify the public key received with the data.
Most efforts which try to explain how to use OpenSSL as a certificate authority fail, and my effort will probably do the same, since the way openssl handles the configuration file, the amount of available subcommands and the complexity of the subject all lead to an almost un documentable mess. What this chapter will do is try to help you setup a functional CA using OpenSSL and then hopefully things will become clear.
The first step is to setup the CA itself, then create a webserver to interface your CA stuff to the world and add everything else that is needed. For me this is the first time that I dived this deed into OpenSSL, so if you have comments or suggestions let me know. Before we dive into setting up the CA we need to create a directory tree that holds our data. Please create the following tree:
/etc/cao/ /etc/cao/CA /etc/cao/CA/db /etc/cao/CA/public /etc/cao/CA/public/ssl /etc/cao/CA/public/ssl/csr /etc/cao/CA/public/ssl/crt /etc/cao/CA/public/nossl /etc/cao/CA/private /etc/cao/CA/private/CA /etc/cao/CA/private/CA/certs /etc/cao/CA/private/CA/keysInside the /etc/cao/CA/db directory create the following files:
echo "101010" > serial echo -n > index echo "101010" > crl_numberThe db directory can be shielded from the world only the one maintaining the CA should be able to access the directory and the files contained therein.
The public directory should be accessable for both the one maintaining the CA and Apache, which we will setup later and the private directory should again be only accessable to the one maintaining the CA.
The next sections quickly introduce some of the basic commands and the configuration file used by OpenSSL. You are not expected to understand what it is all about, it is there for your reference to get back to when you are confused (which will happen) and to have a starting point for the configuration file.
The openssl command is actually a wrapper around other commands, which are the actual commands. For every "subcommand" there is a manual page (and also for openssl itself), so there is enough to read. The most important commands for this document are:
The x509 command is needed to create a certificate authority. All others are needed to create, sign and revoke the certificates we hand out.
Most commands mentioned in 6.1 use the same configuration file: openssl.cnf. The configuration file is devided in sections for the different commands and even for some options to the commands different sections can or will be used, which is very confusing in the beginning. A good overview of the entire openssl.cnf file and its options can be found at http://www.technoids.org/openssl.cnf.html.
Missing from the above mentioned document is a quick overview of which section refers to which command and how it can be overwritten. The following tables completes that:
Parameter | Commandline using the section | Overwrite option | Default | Description | Section |
---|---|---|---|---|---|
default_ca | openssl ca | -name | CA_default | Which CA section to use | ca |
policy | openssl ca | -policy | CA_default | ||
crl_extensions | openssl ca -gencrl | -crlexts | crl_ext | Used when revoking certificates | CA_default |
x509_extensions | openssl ca openssl req -x509 | -extensions | usr_cert | Normal CA extensions | CA_default |
req_extensions | openssl req -x509 | -reqexts | Commented out v3_req | Certificate request | req |
distinguished_name | req_destinguished_name | DN description | req | ||
attributes | req_attributes | DN description | req |
Create the following configuration file as /etc/cao/CA/openssl.cnf (explanations will come in the following chapters):
[ ca ] default_ca = CA_default [ CA_default ] dir = ${ENV::CA_DOMAIN_ROOT} serial = ${ENV::CAO_SERIALDB_FILE} database = ${ENV::CAO_INDEXDB_FILE} certs = ${ENV::CAO_SIGNED_CERTS_DIR} new_certs_dir = ${ENV::CAO_CRT_DIR} certificate = ${ENV::CAO_CACRT_FILE} private_key = ${ENV::CAO_CAKEY_FILE} RANDFILE = ${ENV::CAO_RAND_FILE} crl_dir = ${ENV::CAO_SSL_ROOT} crl = ${ENV::CAO_CRL_FILE} crl_number = ${ENV::CAO_CRLDB_FILE} x509_extensions = usr_cert default_days = ${ENV::DEFAULTDAYS} default_md = ${ENV::DEFAULTMD} preserve = no default_crl_days = 30 nameopt = default_ca certopt = default_ca email_in_dn = no policy = policy [ policy ] countryName = ${ENV::C_POLICY} stateOrProvinceName = ${ENV::ST_POLICY} localityName = ${ENV::L_POLICY} organizationName = ${ENV::O_POLICY} organizationalUnitName = ${ENV::OU_POLICY} commonName = ${ENV::CN_POLICY} emailAddress = ${ENV::EMAIL_POLICY} [ req ] default_bits = ${ENV::KEYBITS} default_keyfile = key.pem default_md = ${ENV::DEFAULTMD} string_mask = nombstr prompt = no # do not ask for DN distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca crl_extensions = crl_ext [ req_distinguished_name ] C = ${ENV::DN_C_DEFAULT} ST = ${ENV::DN_ST_DEFAULT} L = ${ENV::DN_L_DEFAULT} O = ${ENV::DN_O_DEFAULT} OU = ${ENV::DN_OU_DEFAULT} CN = ${ENV::DN_CN_DEFAULT} emailAddress = ${ENV::DN_MAIL_DEFAULT} [ req_attributes ] # [ usr_cert ] basicConstraints = ${ENV::BASICCONSTRAINTS} subjectKeyIdentifier = hash authorityKeyIdentifier = ${ENV::AUTHORITYKEYIDENTIFIER} subjectAltName = email:copy issuerAltName = issuer:copy nsComment = ${ENV::NSCOMMENT} nsCertType = ${ENV::NSCERTTYPE} keyUsage = ${ENV::KEYUSAGE} extendedKeyUsage = ${ENV::EXTENDEDKEYUSAGE} nsBaseUrl = ${ENV::CAO_BASE_URL} nsCaRevocationUrl = ${ENV::CAO_CRL_URL} nsCaPolicyUrl = ${ENV::CAO_CAPOLICY_URL} nsRevocationUrl = ${ENV::CAO_REVOKE_URL} nsRenewalUrl = ${ENV::CAO_RENEW_URL} issuerAltName = URI:${ENV::CAO_CACRT_URL} [ v3_req ] basicConstraints = ${ENV::BASICCONSTRAINTS} keyUsage = ${ENV::KEYUSAGE} [ v3_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = ${ENV::AUTHORITYKEYIDENTIFIER} basicConstraints = ${ENV::BASICCONSTRAINTS} keyUsage = ${ENV::KEYUSAGE} nsCertType = ${ENV::NSCERTTYPE} subjectAltName = email:copy issuerAltName = issuer:copy nsBaseUrl = ${ENV::CAO_BASE_URL} nsCaRevocationUrl = ${ENV::CAO_CRL_URL} nsCaPolicyUrl = ${ENV::CAO_CAPOLICY_URL} nsRevocationUrl = ${ENV::CAO_REVOKE_URL} nsRenewalUrl = ${ENV::CAO_RENEW_URL} issuerAltName = URI:${ENV::CAO_CACRT_URL} [ crl_ext ] authorityKeyIdentifier = keyid:always,issuer:always
Since we use prompt = no the [ req_destinguished_name ] section is a bit different then what you might expect. We do not want openssl to ask the questions, we just provide the data in variables and just assign the values. No questions asked, same goes for the [ req_attributes ] section.
The default MD is sha256, the DEFAULTDAYS is 3650 for the CA certificate and 365 days for normal certificates. And for the policy section we just refer to a single [ policy ] section since this one also uses variables.
To make the integration with a CA website easier (security wise), we decided to create our own directory structure. The structure is defined in the following variables where CAO_ROOT is /etc/cao and the CAO_MY_DOMAIN is CA:
# CAO generic stuff CAO_SSLCNF_FILE=${CAO_ROOT}/${CAO_MY_DOMAIN}/openssl.cnf # Database directory CAO_DB_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/db CAO_SERIALDB_FILE=${CAO_DB_ROOT}/serial CAO_INDEXDB_FILE=${CAO_DB_ROOT}/index CAO_CRLDB_FILE=${CAO_DB_ROOT}/crl_number CAO_RAND_FILE=${CAO_DB_ROOT}/random # Our private directory CAO_PRIVATE_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/private CAO_PRIVATE_CA_DIR=${CAO_PRIVATE_ROOT}/CA CAO_CAKEY_FILE=${CAO_PRIVATE_CA_DIR}/cakey.pem CAO_USRKEY_DIR=${CAO_PRIVATE_CA_DIR}/keys CAO_SIGNED_CERTS_DIR=${CAO_PRIVATE_CA_DIR}/certs # Our public directory CAO_PUBLIC_ROOT=${CAO_ROOT}/${CAO_MY_DOMAIN}/public CAO_NOSSL_ROOT=${CAO_PUBLIC_ROOT}/nossl CAO_CACRT_FILE=${CAO_NOSSL_ROOT}/cacert.pem CAO_SSL_ROOT=${CAO_PUBLIC_ROOT}/ssl CAO_CRL_FILE=${CAO_SSL_ROOT}/crl.pem CAO_CSR_DIR=${CAO_SSL_ROOT}/csr CAO_CRT_DIR=${CAO_SSL_ROOT}/crt
Set directory security:
chown root.apache /etc/cao chmod 750 /etc/cao chown root.apache /etc/cao/CA chmod 750 /etc/cao/CA chown root.apache /etc/cao/CA/public chmod 750 /etc/cao/CA/public chown -R root.apache /etc/cao/CA/public/ssl/ chown -R root.apache /etc/cao/CA/public/nossl/ chmod 750 /etc/cao/CA/public/ssl/ chmod 750 /etc/cao/CA/public/nossl chmod 770 /etc/cao/CA/public/ssl/csr chmod 600 /etc/cao/CA/public/ssl/csr/*
Normally you create a certificate signing request (CSR) for e.g. your web-server containing the public key and sent that to a CA. The CA signs your request and sents you back a certificate (CRT) that you can use. Since we want to understand how this whole process fits to gether we need to create our own CA. A logical problem with certificates is: Who is going to make sure the certificate of the CA is trusted? This catch 22 is solved by so called self signed certifictates. The CA creates it's own certificate which is called a root certificate. To create such a root certificate we first need to create a private key for the CA. This key is used to create a CSR and with that same key we can sign our own certificate.
For normal certificates one would use the openssl ca command. For selfsigned certificates however you need the x509 command. Creating it with the ca command gives you also a selfsigned certificate, but that one is not accepted by Microsoft AD as a root certificate. The only self signed root certificate we could create that worked on both GNU/Linux and AD is with the following commands, but first we need to set the CA specific variables:
BASICCONSTRAINTS="CA:TRUE,pathlen:0" AUTHORITYKEYIDENTIFIER="keyid:always,issuer:always" KEYUSAGE="cRLSign,keyCertSign,digitalSignature" NSCERTTYPE="sslCA,emailCA,objCA" EXTENDEDKEYUSAGE="1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4,1.3.6.1.5.5.7.3.8,1.3.6.1.5.5.7.3.9" C_POLICY=match ST_POLICY=match L_POLICY=match O_POLICY=match OU_POLICY=optional CN_POLICY=supplied EMAIL_POLICY=optionalWith these specific settings we can generate the key and the certificate:
openssl req -config ${CAO_SSLCNF_FILE} -new -newkey ${KEY}:${KEYBITS} -out ${CAO_CACRT_FILE%.pem}.csr -keyout ${KEY_FILE} openssl x509 -trustout -extfile ${CAO_SSLCNF_FILE} \ -extensions v3_ca \ -days ${CADAYS} -signkey ${KEY_FILE} \ -trustout -req -in ${CAO_CACRT_FILE%.pem}.csr \ -out ${CAO_CACRT_FILE} -outform PEMAs you can see we tell x509 through the -extfile option where our openssl.cnf file is and that it needs to use the v3_ca section to create the certificate.
Certificates (and RSA keys) can be stored in different formats. The most comman formats are DER and PEM. DER is a binary format mainly used by Java and Macintosh platforms, and PEM is a base64 representation of DER with header and footer information mainly used by UNIX-like systems. There is also an absolete NET version (Netscape server), which was used by earlier versions of IIS up to 4.0.
To also create the DER form:
openssl x509 -in ${CAO_CACRT_FILE} -outform DER \ -out ${CAO_CACRT_FILE%.pem}.derAnd the last part is that some applications also need the hashed version available from the CA: CAO_CA_HASH=`openssl x509 -noout -hash -in ${CAO_CACRT_FILE}` cp ${CAO_CACRT_FILE} ${CAO_CACRT_FILE%/*}/${CAO_CA_HASH}.0
To view the contents of this key use:
openssl rsa -noout -text -in cakey.pem
To view the contents of the certificate use:
openssl x509 -noout -text -in cacert.pem
As a CA we can sign certificates and also revoke them. To be able to tell the world what certificates are revoked or to give people a way of submitting a CSR we need an interface to the world. This interface for our project consists of a web server. Since we are dealing with sensitive data we want to communicate in a secure manner and thus need to support the HTTPS protocol. The first certificate we will thus create will be for our own server. For a server certificate we need the following variables:
BASICCONSTRAINTS="CA:FALSE" AUTHORITYKEYIDENTIFIER="keyid,issuer:always" KEYUSAGE="nonRepudiation,digitalSignature,keyEncipherment" C_POLICY=optional ST_POLICY=optional L_POLICY=optional O_POLICY=optional OU_POLICY=optional CN_POLICY=supplied EMAIL_POLICY=optional
We then need to create a new key for our server:
openssl genrsa -${DEFAULTMD} -out serverkey.pem ${KEYBITS}
This key is going to be used by our webserver. We do not want to type our passphrase everytime that our server starts, so we create a key without a passphrase:
openssl rsa -in serverkey.pem -out serverkey-insecure.pemSince there is no passphrase on the key, it is highly insecure, thus we have to protect it:
chmod 0400 serverkey-insecure.pem
The next step is to create a certificate signing request (CSR):
openssl req -config openssl.cfg -new -key serverkey-insecure.pem \ -out servercert.csr
The last step is for our CA to sign the certificate:
openssl ca -config openssl.cnf -days 365 -cert cacert.pem \ -keyfile cakey.pem -in servercert.csr -out servercert.pem -batch
Now the infrastructure of our CA with regards to certificates and keys is inplace.
Now that we have a self signed certificate, we can operate as a CA and sign CSRs. There is however one more thing we should do and that is to create a public CA interface.
It might happen that a private key of a server gets stolen, so we need the ability to revoke a certificate to tell the whole world that the certificate is not valid anymore. As a CA we are responsible for this information, since we are the one that tells the world that a certain server can be trusted.
For this public interface we need a webserver and we need to tell the world where they can get the information. The current standard is by using a so called Certificate Revocation List (CRL).
Example apache configuration:
<VirtualHost ca.example.com:80> ServerName ca.example.com ServerAdmin webadmin@example.com DocumentRoot /etc/cao/CA/public/nossl/ </VirtualHost> <IfModule !mod_ssl.c> LoadModule ssl_module modules/mod_ssl.so </IfModule> <IfModule mod_ssl.c> <VirtualHost 192.168.1.1:443> ServerName ca.example.com ServerAdmin webadmin@example.com DocumentRoot /etc/cao/CA/public/ssl/ ErrorLog logs/ssl_error_log TransferLog logs/ssl_access_log LogLevel warn SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0 CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" SSLEngine On SSLCipherSuite SSLv2:-LOW:-EXPORT:RC4+RSA SSLCertificateFile /etc/cao/CA/private/CA/certs/ca.example.com.pem SSLCertificateKeyFile /etc/cao/CA/private/CA/keys/ca.example.com.key SSLCACertificateFile /etc/cao/CA/public/nossl/cacert.pem # SSLCertificateChainFile /usr/local/var/openca/crypto/chain/cacert.crt # SSLCARevocationFile /usr/local/var/openca/crypto/crls/cacrl.pem </VirtualHost> </IfModule>