SSL-Manual
Gepost in /PHP ontwikkeling/Software op 29 Juni 2012Deze blog is geschreven door Christiaan Schaake
Preface
This guide explains how to setup a root certification authority (CA) on Linux, and how to implement
apache ssl on Linux.
A Certification Authority (CA) holds a self-signed key that is able to sign other keys. Large commercial CA's like
Verisign use this exact same procedure as described in this document. Only these commercial CA's have installed there
root certificate within the most browsers, so you don't have to manually install the root certificate of Verisign.
Microsoft and Netscape did already do this for us.
You can use a Verisign certificate for your own HTTPS server, but this is very expensive. We can create our own
CA, the only thing your visitors have to do is install your root certificate. We can use our CA
to sign any certificate, like for HTTPS, SSH, VPN, E-Mail and any other application that can use a certificate.
Certificates explained
Certificates are a way to encrypt and decrypt information without first discussing the encryption key and
authenticating the identity of the sender. In the past when someone wanted to send an encrypted message to another person,
both the sender and the receiver had to agree on a secret encryption key. They had to find a way to secretly pass the
encryption key to each other.
E.g. Bob wants to send Alice a message. Bob and Alice agree to send the words in the message backwards (ok, this
is easy to hack, but it's just an example). Bob send "olleh" to Alice. Alice knows that the message must be reversed
to decrypt it, so Alice reads "hello". Mallod is listening to the messages between Bob and Alice does not understand
the message since he reads only the "olleh" message, and he does not know the secret encryption key Alice and Bob
have agreed on. (Ok, Mallod must be a complete idiot not to guest the key...).
The big disadvantage of this method is that both the sender and receiver must know the exact encryption key before
they can start communicating. And how can you be sure that nobody else will 'hear' what you agree on.
Modern methods of encrypting data is based on key pairs. A key pair consists of a private key and a public certificate.
Messages encrypted by a private key can only be decrypted by its public certificate, and visa versa. The way this is done
is an extreme complex mathematical algorithm which is based on prime numbers.
So know if Bob wants to send Alice a message, Bob has to encrypt the message with the public certificate of Alice. Now only
Alice can decrypt the message since she is the only one who knows the private key. if Mallod was not as stupid as
we thought before, he could try to hack the encrypted message by trying a random key.
The most keys used on the Internet contain a minimum of a 1024 bytes key. So Mallod has a chance of 1 to
1,208,925,819,614,629,174,706,176.
Ofcource Alice has to publish her public certificate so Bob can use it. But Alice doesn't have to be afraid that anyone
can misuse her public certificate. Without the private key, the public certificate is useless for a hacker.
If Alice wants to send a message back to Bob, she has to use Bob's public certificate to encrypt the message. If Alice uses
her private key to encrypt the message, Bob can also decrypt the message using Alice's public certificate, but also can
everyone else!
Signing explained
With only a certificate we can encrypt and decrypt information, but sometimes you only want to know is the person
you are talking with is really the person that is tells you he is. The person can encrypt data and send it to you. if
you have his public certificate, you know only he could encrypt data. But where did you get his public key from? E.g. on HTTPS
the server itself sends you its public certificate when you make your initial contact.
To make sure that a person is really the person he says he is, you would like to ask someone who you can trust. This
is exact what signing is about. A certificate can be signed by a Certification Authority (CA). A CA is nothing more
than an organization that gives out a signature saying that the holder of the signature is checked by this organization.
When you connect to a bank using HTTPS, the bank server will send you its public certificate at the initial connection. But
this public certificate is signed by a CA. So this public certificate holds an encrypted message from the CA, which is
encrypted using the CA's private key. Your browser uses the CA's public certificate to decrypt this CA's message in the
banks certificate.
The CA's message contains some information about the banks server, e.g. the domain name. Your browser checks this
information with the banks server. E.g. the CA's message tells you that the banks domain name is www.bank.com, so
if the banks server suddenly uses www.bogus.com, you will know that the 'misconceived' bank server is now the server
it tells you it is.
Single Sign On
Signing can not only be used to authenticate servers, but can also be used to authenticate a client or user. When a
number of servers are used for 1 single company or task. It would be very unpleasant to login on all servers individually.
You can create your own personal certificate pair and sign them at a CA. Now you can store your personal public certificate
in all the servers and tell those servers that this certificate belongs to your login code. Now when you connect to one of these
servers, you send your public certificate encrypted using your private key to the server instead of sending your user-name and password.
The server decrypts your encrypted public certificate using your stored public certificate and checks this certificate against the stored
certificate. if the certificates match, you are logged in.
An other way to handle a larger group of users is to configure the server so that it will accept all users with a personal
certificate that is signed by a specific CA. Normally this is a special CA and not a public one. So only the CA has to check that
a users is valid to use a specific application. The server checks the CA to see if a user is permitted to connect.
This is where directory services (like Microsofts Active Directory) come in handy.
SSL explained
The basic functionality of SSL (Secured socket layer) is to:
- Encrypt confidential information to ensure that only the right receiver can read the information.
- Verify the data integrity so that the receiver is sure the data is not modified.
- Authenticate the server so the user is certain the data came from the server.
A certificate can also be used to sign another certificate. The first certificate in the chain is called the root certificate.
This root certificate is a so called self-signed certificate. Other certificates are signed using this root certificate.
The process for generating a certificate that is signed by a root certificate, you will have to follow the next procedure:
- Generate a private key
- From the private key, generate a certification request for the CA
- The CA signs the public key in the certification request
- Install the signed public key
Certificates are only valid for a period of time, mostly 1 year. After this period the certificate has to be renewed. It is also possible that the CA revokes the certificate. This means that the certificate is no longer valid although it is not passed the expiring date.
Certificate files
Certificates and keys are stored in files. There are some major certificate formats which can be recognized by there file extension.
- .cer .crt .der - Binary encoded certificate.
- .pem - Base64 encoded DER certificate.
The certificate is enclosed between "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" - .p12 - PKCS#12 standard container file which may contain several public certificates and (password protected) private keys
The .p12 file is often used to transport a new signed key and certificate to be installed on e.g. a web-server. The .p12 file can include the complete root chain with the certificate and key.
OpenSSL
The most commonly used tool for managing certificates is OpenSSL. OpenSSL is available on most Linux distributions or can be installed easily. OpenSSL uses a common directory structure on most Linux systems. The directory structure is as followed organized:
Directory | Permissions | Description |
---|---|---|
/etc/ssl/certs | world readable | Contains all known public certificates |
/etc/ssl/signedcerts | world readable | Contains all signed public certificates signed by local implementation |
/etc/ssl/newcerts | world readable | Contains all created public certificates (internal database) |
/etc/ssl/requests | world writable | Contains all signing requests for local implementation |
/etc/ssl/private | secured | Contains all private keys, must not be world accessible! |
The configuration of OpenSSL is stored in /etc/ssl/openssl.cnf. This configuration file can be used to store the OpenSSL preferences.
So if you don't want to use the default directories you can change them in here.
The structure of the openssl.cnf is complex. Configuration blocks are identified by [] signs, e.g. [ req ] for executing signing requests.
Blocks can refer to other blocks. A common configuration file includes a [ ca ] block that refers to a [ CA_default ] block.
Entry points for the most common requests are:
- [ ca ] - Entry point for signing a request with a CA key
- [ req ] - Entry point for creating a signing request
- [ v3_req ] - Called from the req block
- [ v3_ca ] - Called from the req block when openssl is called with the -x509 option
- [ crl_ext ] - Called from the ca block when crl_extensions attribute or -crlexts option is used
On the web a more detailed description of the options in the openssl.cnf file can be found.
Create root certificate
The root certificate is used to authenticate all other certificates that are generated using the root certificate.
This way only the root certificate must be installed in e.g. the Internet browser and all other certificates are
than authenticated.
The root certificate is made up by a private key and a certificate, just like any other certificate. The root certificate
is a so called self signing key, except that the DN (common name) is not the website but an describing name (e.g. Schaake root Certificate).
The cakey.key is the private key and must be kept save, since this will be the server key to sign other keys. And you
don't want others to be able to sign your keys!
It is a good habit to store a CA Root private key off-line, e.g. on a flash drive, and store it in a save.
The cacert.crt is the public key, this key must be installed in a visitors browser. So publish this key on your website.
openssl req
-new -x509
-newkey rsa:2048 -sha256
-keyout /etc/ssl/private/cacert.key
-out /etc/ssl/signedcerts/cacert.pem
-days 3650
-config /etc/ssl/openssl.cnf
This command generates the self-signing key request and will generate the private key and public certificate. Copy
the public certificate (cacert.pem) to a location on your website for distribution.
We request a new x509 certificate with a RSA algorithm and a key-length of 2048 bytes. Next we will use a sha2 hash, the
default MD5 is easily hacked, all modern software can handle the new sha2 hashes.
The option days will set the number of days the certificate will remain valid. Normally we would like to set it to only
1 year. But we don't want our visitors to install a new root certificate every year. And we also don't want to create
new certificates for all services every year. So only for the root certificate, set the expiring period to 10 years.
Certificate request
Most applications can create there own certification request, but we can also do this using the openssl command. On the common name (CN) enter the hostname, email address or application name that is going to use this certificate. You have to supply the exact name in the DN field, since this is the only field that is checked to see if the certificate belongs to this source.
openssl req -new
-keyout /etc/ssl/private/www_myserver_dom.key
-out /etc/ssl/requests/www_myserver_dom.csr
-days 365 -config /etc/ssl/openssl.cnf
The .key file is the private key (keep this save). The .csr file is the certification request. This includes the public
key and all other information about the request.
Normally you would send this file to the CA.
This command will ask a number of questions. The most import question is the Common Name (CN). The CN must be exactly
similar to the domain name of the server that will use the certificate (e.g. www.myserver.dom).
Sign a certificate
The next step is to sign the certificate. We use the certificate request to create a signed certificate.
openssl ca
-out /etc/ssl/signedcerts/www_myserver_dom.pem
-infiles /etc/ssl/requests/www_myserver_dom.csr
The request already includes the name of the CA to be used to sign the request.
File conversion
The generated files are normally in PEM format. Some software however requires different file formats. Existing certificates and key files can be converted to other formats using openssl commands.
PEM to DER
Convert PEM to DER format:
openssl x509 -inform der -in mycertificate.der -out mycertificate.pem
DER to PEM
Convert DER to PEM format:
openssl x509 -outform der -in mycertificate.pem -out mycertificate.der
PEM to PKCS#12
Create a p12 container including the certificate and (protected) private key:
openssl pkcs12 -export
-in mycertificate.pem -inkey mykey.key
-out mykeystore.p12 -name "www.myserver.dom"
Create a p12 as above but also include the signing ca certificate, so include a complete chain:
openssl pkcs12 -export
-in mycertificate.pem -inkey mykey.key
-out mykeystore.p12 -name "www.myserver.dom"
-CAfile myCaCertificate.pem -caname myCaName -chain
The parameters -CAfile and -caname can be repeated for every intermediate certificate, when applicable.
PKCS#12 to PEM
Convert the p12 container to a PEM file that contains both public certificates and the private key.
openssl pkcs12 -in mykeystore.p12 -out mykeystore.pem -nodes
Another option is to create a new file and copy the contents of all PEM and key files into this new file.
Checking certificates
One of the complexities with certificates is to find out if they are correct and what they can be used for. The next command will check a certificate and give it's usage options.
openssl x509 -in /etc/ssl/signedcerts/www_myserver_dom.pem -text -noout -purpose
A certificate that can be used as Server certificate will print 'SSL Server = Yes'. SSL Client certificates can be used as a client certificate for authentication (2 side SSL). A S/MIME signing can sign an email.
Another way to easily check certificates is by opening a .crt file in Windows. A .pem file can just be renamed to .crt. Windows will show the details of the certificate. It is not necessary to install the certificate.
Revocation list
Signed certificates are valid for a predetermined time period, commonly one year. But it can be useful to recall a certificate
before its validity end time. A reason could be that a key gets stolen, or you simple don't want a user to use the key anymore.
There is a mechanism call certificate revocation list. A CA can have a special list that contains certificates which are revoked.
Normaly this revocation list is published on the CA's website. A link to this revocation list is included in the CA's certificates.
It is easy to configure a revocation list in the configuration file of OpenSSL. The OpenSSL configuration file (openssl.cnf) contains sections.
First we need to tell OpenSSL to include a crl in the root certificate.
[ CA_default ]
crlnumber = $dir/crlnumber
crl = $dir/ca.crl
copy_extentions = copy
crl_extentions = crl_ext
This tells OpenSSL to include the section crl_ext into the CA request. Next is the crl_ext itself:
[ crl_ext ]
basicContraints - CA:FALSE
keyUsage = digitalSignature, keyEncipherment
authorityKeyIdentifier=keyid:always,issuer:always
crlDistributionPoints = URI:http://mywebsite.dom/ca.crl
This section tells openssl how to use the crl extension.
Revoke a certificate
We can revoke a certificate. The certificate will become invalid, but the client application needs to check the CA's certificate revocation list. Not all clients use this functionality. It is e.g. possible to manually load crl files into a web-browser. But if this action is never done, revoked certificates will remain valid for the client.
The command to revoke a certificate is:
openssl ca -revoke /etc/ssl/signedcerts/www_myserver_dom.pem
The next this is to publish an updated crl file. The crl file will be generated with the next command:
openssl ca -gencrl -out /etc/ssl/crl/myca.crl
The only thing left is to copy this crl file to the endpoint provided in the certificates, in our example http://mywebsite.dom/ca.crl
Apache Server Authentication
A certificate can be used to validate the authenticity of a web-site. This guaranties the visitor of a web-site that the web-site is the
actual web-site it says it is. And all traffic to and from this web-site is encrypted.
First we need to generate a certificate and key pair for the web-site. We can use a self-signed certificate or a certificate signed by our own
CA key. But a good option is to look for a cheap CA that is generally trusted.
For now we assume we have a certificate and key signed by a CA. Apache uses different configuration files for different sites. The secured site will
get its own site. Both the unsecured as the secured site can however point to the same directory structure.
First step is to enable the apache SSL module by copying ssl.conf and ssl.load from mods-available to mods-enabled directory under /etc/apache2.
Next we can copy the default configuration file in /etc/apache2/sites-enabled/000-default to e.g. 000-secure. The newly generated configuration
file needs the following changes:
<virtualHost _default_:443>
SSLEngine on
SSLProtocol +SSLv3 +TLSv1
SSLCertificateFile /etc/ssl/certs/www.myserver.dom.pem
SSLCertificateKeyFile /etc/ssl/private/www.myserver.dom.key
SSLCertificateChainFile /etc/ssl/certs/myCA-bundle.pem
The first option is to enable the SSL engine. Next we only want the secure SSLv3 or TLSv1 protocols. We need to specify the certificate and
the key. The last option is to include the CA's certificate bundle (all the certificates that make up the chain of our certificate).
Restart the web-server to enable the new configuration. On server start the private key password must be entered.
Apache client authentication
Now that we have the web-server running on SSL, we want to check for a valid client certificate. We do not just want to accept any signed certificate. Anyone can create a self-signed certificate. We want to check for a client certificate signed by a trusted CA. Assume a client certificate is been created using our own CA. The next configuration parameters must be added to the apache HTTPS configuration (/etc/apache2/sites-enabled/000-secure):
SSLVerifyClient optional
SSLVerifyDepth 5
SSLCACertificateFile /etc/ssl/certs/trustedCAClients.pem
The first option tells Apache to ask for a client certificate. If no certificate is present, the user can still access the web-site. We could
use the option 'require' instead of 'optional' to force the visitor to use a valid client certificate. The visitor will be denied access without
a valid certificate.
The next parameter specifies the maximum chain dept. And the last specifies a bundle file containing all trusted certificate signers (CA's).
After a restart of the server we should be able to login to the server with our client certificate. A web browser will only display a client certificate if a client key is installed which confirms to the server's CA specified in the SSLCACertificateFile.
Common errors
A client certificate is not presented when accessing the site.
- Check if the client certificate is installed as personal certificate.
- Check if the client certificate can be used as client certificate. See Checking certificates.
- Check the server error log (/var/log/apache2/ssl_error_log) for errors.
- Check the server access log (/var/log/apache2/ssl_access_log) to find further clues
Client Authentication in PHP
Normally web-sites use username and password combinations for visitors to login to the web-site. There is a easier way to automatically login
to web-sites using the client certificate. In the previous chapter we setup the Apache web-server to only accept client certificates that
were signed by our CA. Only certificates given out by the CA can use there certificate to use the certificate for 2-side encryption.
Certificates have a new CN that contain an unique name. We can identify the user by the CN in the client certificate.
By default the certificate information is not passed to the PHP script. So we need to tell Apache to forward this information. In the Apache configuration file (000-secure) we need to add the next parameter:
SSLVerifyClient optional
SSLVerifyDepth 5
SSLCACertificateFile /etc/ssl/certs/trustedCAClients.pem
SSLOptions +StdEnvVars
PHP will get the SSL details from both the server and client certificate in the global $_SERVER variable. The CN is located in $_SERVER['SSL_CLIENT_S_DN_CN']. For security we can check the client certificate signing authority is located in $_SERVER['SSL_CLIENT_I_DN_CN'].
Combined client certificate and Basic authentication with Apache and PHP - Need to be revised!
This chapter describes how to setup client certificate authentication combined with Basic Authentication when no valid
client certificate was given.
First setup a Root CA and Apache SSL before you can continue.
Now create a client certificate. First create a certificate request (as shown in a previous chapter).
Only set the CN (or Common Name) to a user name you want the certificate to be used for. Sign the certificate, and now you
have a private and public pair for your client certificate.
for some reason all webbrowsers only accept pk12 certificates, so you have to convert the certificates using the next command.
openssl pkcs12 -export -in /var/ssl/certs/cc-test.crt \
-inkey /var/ssl/private/cc-test.pem \
Now you can import this client certificate in any webbrowser.
-out /var/ssl/certs/cc-test.p12 \
-name "Test Client Certificate"
Next we have to configure is the web server. for our test we will use a specific directory for testing purposes.
So make add the next location in you httpd.conf, we are going to use https://www.webserver.com/cert as testing area.
<Location /cert>
Now we can connect to this directory with our certificate. if things won't work, check your server logfiles. And make sure
you have configure you server for SSL. (TIP: Check your servers DNS name, this must be the same as in the CA certificate use for
signing your client certificate).
# Client authentication stuff
SSLVerifyClient optional # Can be optional or required
SSLVerifyDepth 2
SSLOptions +FakeBasicAuth # I'm not sure about this option
</Location>
Now we only have to build a script to check if the certificate is valid, and if no certificate was provided, do basis authentication.
<?
What you will have to include yourself is:
// Check if and how we are authenticated
if ($_SERVER['SSL_CLIENT_VERIFY'] != "SUCCESS") { // Not using a client certificate
// Not logged in using basic authentication
if ((!$_SERVER['PHP_AUTH_USER']) && (!$_SERVER['PHP_AUTH_PW'])) {
authenticate(); // Send basic authentication headers
}
}
if ($_SERVER['SSL_CLIENT_S_DN_CN'] != "chris") { // Check CN name of cert
// Check username and password
if (!(($_SERVER['PHP_AUTH_USER'] == "test") &&
($_SERVER['PHP_AUTH_PW'] == "123"))) {
authenticate(); // Send basic authentication headers
}
}
phpinfo();
// ------------------------------------------------------------------------
// authenticate()
//
// Call authentication display
// ------------------------------------------------------------------------
function authenticate() {
Header("WWW-Authenticate: Basic realm=Website");
Header("HTTP/1.0 401 Unauthorized");
error401();
exit;
}
?>
- Certificate to user mapping
- Username/password checking
A good solution would be an LDAP directory for both tasks. And you have to make sure your users can easilly revoke
there certificate when it has being stolen. Apache will take care of the certificate checking including the check if the
certificate was revoked, if configured correctly...
A number of browsers can have an additional password on the certificate, so a user will have to enter a password when
the server requists the client certificate. But this is an optional service, so don't depend on it.
You could also do a client certification check and a username password check, just mixup the script...