SSL, TLS and Certificates

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.

1. Introduction

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.

1.1 SSL and TLS

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 ...
As the SSL name implies it uses it's own socket, meaning every secure service uses it's own port to listen on:
Normally a service gets a 's' attached to is name to imply a secure service, like in https or ldaps, but there are exceptions like smtp that is called ssmtp. See your /etc/services file for the correct naming and used ports.

2. MAC

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 -sha1
Changing 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 -md5
You will note that even removing the newline will dramastically change the output.

3. Encryption and decyption

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.

3.1 Symmetric-key Encryption

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.pem
To see what is generated use:
openssl pkeyparam -in dhp.pem -text
Which 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.pem
You can view both generated keys with (replace alice with bob to view Bobs keys):
openssl pkey -in dhkey-alice.pem -text -noout
As 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.pem
Eve listening on the line reads the public keys:
openssl pkey -pubin -in dhpub-bob.pem -text
With 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.bin
And 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

3.2 Public-key Encryption

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 1024
Where -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.pem
With cat you can view the contents of the files.

3.3 Random number generator

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:


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.

4. Digital Signing

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?

5. Certificates

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.

6. About OpenSSL

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:

Inside the /etc/cao/CA/db directory create the following files:
echo "101010" > serial
echo -n > index
echo "101010" > crl_number
The 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.

6.1 The openssl command

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.

6.2 The openssl.cnf file

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

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:
ParameterCommandline using the sectionOverwrite optionDefaultDescriptionSection
default_caopenssl ca-nameCA_defaultWhich CA section to useca
policyopenssl ca-policy  CA_default
crl_extensionsopenssl ca -gencrl-crlextscrl_extUsed when revoking certificatesCA_default
x509_extensionsopenssl ca
openssl req -x509
-extensionsusr_certNormal CA extensionsCA_default
req_extensionsopenssl req -x509-reqextsCommented out v3_reqCertificate requestreq
distinguished_name  req_destinguished_nameDN descriptionreq
attributes  req_attributesDN descriptionreq

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.

6.3 The variables

Is the root where everything related to the default CA is stored.
Contains the path and filename of the serial file.
Contains the path and filename of the index file.
Contains the path to the directory where the signed certificates are stored
Constains the path to the directory that holds the signed certificates, where the crts are stored by serial file name. This directory will be available via the web interface in a secure manner (SSL).
Path and filename for the CA certificate
Path and filename of the CA key
Path and filename of the random file
The path to the directory that will function as the document root of the SSL website.
Path and filename of the Revocation List
Path and filename of the version number database for the CRL
The amount of days that a certificate is valid. CAO uses 365 for normal certificates and 3650 for the CA certificate.
The MD to be used.
The amount of bits used when generating a key
The policy for the Country setting
The policy for the State setting
The policy for the Location setting
The policy for the Organization setting
The policy for the Organizational Unit setting
The policy for the Canonical Name setting
The policy for the e-mail setting
The Country setting
The State setting
The Location setting
The Organization setting
The Organizational Unit setting
The Canonical Name setting
The e-mail address setting
The restrictions placed on the certificate (CA or non-CA)
Where the certificate is good for
Where the certificate is good for
Where the certificate is good for
Where the certificate is good for
Text field that describes the certificate
The basic URL for accessing the CA
The URL for accessing the CRL
The URL for accessing the CA policy file
The URL for accessing the CA to revoke a certificate
The URL for accessing the CA to renew a certificate
The URL for accessing the CA certificate

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.

6.4 Creating the directory structure

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
# Database directory

# Our private directory

# Our public directory

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/*

7. Creating a Certificate Authority

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:

With 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 PEM
As 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}.der
And 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

7.2 Making the certificate for our webserver

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:


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.pem
Since 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.

7.2 Public CA interface

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:

    DocumentRoot /etc/cao/CA/public/nossl/
<IfModule !mod_ssl.c>
    LoadModule ssl_module modules/
<IfModule mod_ssl.c>
        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/
        SSLCertificateKeyFile   /etc/cao/CA/private/CA/keys/
        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