A lot of tutorials, a lot of pages, a lot of question and they differ in implementation of this issue "Configure SSL Mutual (Two-way) Authentication". I have to do it with Linux, and I don't know from where to start or what instructions to follow.

What I have to do is:

  • I have a server and many clients, they can access code on server only if they have a signed certificate from server.
  • server can generate those certificates and disable them main server would be the CA .. that means it has to generate certificates for others and then sign them.

I had figured what to do

  1. generate CA certificate
  2. generate certificates for other users.
  3. give certificate to users.
  4. sign certificates.
  5. verify certificate.
  6. regenerate certificate for user or disabled.
  7. user can just sign from one device. (certificate mustn't be copied)

Have I missed something? do I have to be a root user ? is there's any ready bash for this ? where can i find it.why there's more than one openssl.cnf file on linux? where I should put CA certificate any information would be appreciated .

  • 11
    I'm all for downvoting questions you don't feel are of sufficient quality for StackExchange, but please leave an explanatory comment! A downvote alone leaves no constructive feedback, which is especially important for new users.
    – Polynomial
    Apr 26, 2013 at 15:28
  • 1
    Thanks :$ , it's my first security task and I'm totally lost. sorry for my beginner question .
    – SafeY
    Apr 26, 2013 at 18:35
  • One thing that could be clarified here, was this for a totally Linux environment, or for Windows PCs connecting to a Linux website by mutual authentication? I came on this post after being tasked with the latter, with the Linux site already up. I was going to post what I ended up doing that worked, but I didn't want to be offtopic.
    – vapcguy
    Sep 19, 2017 at 16:40

1 Answer 1


There is a handy script distributed alongside openssl, CA.sh to do most of this stuff. Its location is distribution specific. In Debian and derivatives you can locate it using:

# apt-file search CA.sh
openssl: /usr/lib/ssl/misc/CA.sh

And RedHat and derivatives the (approximate) equivalent is:

# yum provides */CA
1:openssl-1.0.1e-4.fc18.x86_64 : Utilities from the general purpose cryptography library with TLS implementation
Repo        : @updates
Matched from:
Filename    : /etc/pki/tls/misc/CA

This is a very simple bash script that eases the creation of the directory structure needed to manage a CA (this is described in the [ CA_default ] section of openssl.cnf). I recommend you to use it and look at the code to learn what it is actually doing.

# ./CA.sh -help
usage: ./CA.sh -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify

This script will use the defaults provided in openssl.cnf, and/or you can provide one configuration file as an argument to the openssl $command using the -config switch if not using CA.sh. The location of the openssl.cnf file is also distribution specific, and you can use the same commands above to find it. The one you want is the one provided by the openssl package.

You probably want to modify the following sections:

[ CA_default ]
default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL

[ req ]
default_bits            = 2048

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = AU
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Some-State
localityName                    = Locality Name (eg, city)
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Internet Widgits Pty Ltd
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd
organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64
  • Generate the CA

Once you have edited openssl.cnf to match your needs, you can generate a CA certificate. Depending on whether you need this CA signed by an recognized third-party CA or not, you can generate a self-signed CA or a CSR to be submitted for signing.

./CA.sh -newca

You will be interactively prompted to ask some questions, the defaults will appear between square brackets. You will recognize the options you modified in openssl.cnf here.

  • Generate a certificate for the server

You can create a certificate request for the server using the same script:

./CA.sh -newreq

Again, you will be prompted to ask several questions, the most important is the Common Name of the certificate, which must match the DNS resolvable name for the IP of the server (or you can use other means, like /etc/hosts, not recommended, hard to maintain and scale)

What you will obtain is a Certificate Signing Request (CSR for short). This will be signed by the Certificate Authority (CA) you created before.

./CA.sh -sign

  • Generate certificates for the clients

Repeat the steps of creating a CSR and getting it signed by the CA. When doing so, pay close attention to how you fill in the Common Name, Organization and Organizational Unit fields, as those will be required afterwards in order to configure the server.

A neat way to distribute the client certificates alongside their respective private keys and the CA certificate is using p12 bundles:

openssl pkcs12 -export -in Certificates/client.pem -inkey client.key -certfile CA.pem -out clientcert.p12

  • Configure the server

Let's suppose the server you are referring to is an Apache web server. Once you have the server certificate, you configure the appropriate VHOST to serve whatever content is going to be protected by mutual SSL authentication. An example could be this phpmyadmin virtual hosts. This is working in an Apache 2.4 server, so please don't use it as-is and carefully review and test it to adapt it to your needs.

Listen                   443 https

  DocumentRoot           "/srv/www/html"
  ServerAdmin            [email protected]
  SSLCACertificateFile   /etc/pki/CA/cacert.pem
  SSLCertificateFile     /etc/pki/tls/private/phpmyadmin.company.com/newcert.pem
  SSLCertificateKeyFile  /etc/pki/tls/private/phpmyadmin.company.com/newkey.pem
  SSLCARevocationCheck   chain
  SSLCARevocationFile    /etc/pki/CA/crl/crl.pem
  SSLEngine              on
  SSLStrictSNIVHostCheck on
  SSLVerifyClient        require
  SSLVerifyDepth         5
  ServerName             phpmyadmin.company.com
  RewriteEngine          on
  RewriteCond            %{REMOTE_ADDR} !^127\.0\.0\.1$
  RewriteCond            %{HTTPS} !=on
  RewriteRule            . - [F]
  Alias                  /console /usr/share/phpMyAdmin
  ErrorLog               "|/usr/sbin/rotatelogs -L /var/log/httpd/phpmyadmin/error.log -f /var/log/httpd/phpmyadmin/error.log.%Y%m%d 86400"
  CustomLog              "|/usr/sbin/rotatelogs -L /var/log/httpd/phpmyadmin/access.log -f /var/log/httpd/phpmyadmin/access.log.%Y%m%d 86400" logstash_json
  <Directory /usr/share/phpMyAdmin/>
    Require              ssl
    Require              ssl-verify-client
    SSLOptions           +FakeBasicAuth +StrictRequire
    SSLRequire           %{SSL_CIPHER_USEKEYSIZE} >= 256
    SSLRequire           %{SSL_CLIENT_S_DN_O} eq "Awesome Company" \
                     and %{SSL_CLIENT_S_DN_OU} eq "Development" \
                     and %{SSL_CLIENT_S_DN_CN} in {"John Doe", "Jane Doe"}
    SSLRenegBufferSize   131072

You can use as many per-directory access control as you need, the important part is that the client certificates shown must comply with the restrictions imposed by the SSLRequire directives, i.e., they must match the Organization, Organizational Unit and Common Name conditions (or other fields of the certificate as you see fit). These fields are taken from the client certificates.

  • Generate a Certificate Revocation List

In order to be able to revoke access to a client certificate, you need to generate a CRL. The command to do it (provided you in the top of the CA directory structure):

openssl ca -config /path/to/openssl.cnf -gencrl -out crl/crl.pem

Afterwards, you revoke client certs as needed using:

openssl ca -config /path/to/openssl.cnf -revoke clientcert.pem


OpenSSL online documentation and Apache online documentation.

  • Thanks , I'll try it now . I did it with openssl commands without any bash :)
    – SafeY
    Apr 29, 2013 at 8:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .