This is a beginner’s overview of how authentication in SSL/TSL works (which by now should be called TLS certificates, but old habits die hard), it is also a short tutorial on how to generate SSL/TLS certificates using OpenSSL, either self-signed or signed by a CA.
As a disclaimer, getting security wrong is very easy, and I’m not an expert. If your systems handle anything vital such as credit card information (1), payments (2), personal information (3), weapons systems (4), etc (5), then hire an expert, use already available services, and reuse libraries from reputable sources. This tutorial is NOT going to make you an expert on SSL/TLS, not even a novice, it will just make you able to understand to a basic level what you’re talking/hearing about. Things that are essential to TLS secure setup and that are NOT addressed here include:
- How to secure your keys
- How to provision them
- How to secure your servers
- What protocols/algorithms/ciphers/modes of operation should your server allow
- A whole lot more
Seriously, security is bigger than just encryption and authentication. Be very mindful about how much the information/services that you administer are worth, what could happen if they were compromised, and to whom. Then consider carefully if you need to hire an expert or educate yourself more in the subject, security breaches can seriously f@#* you up, your close ones, and people you don’t even know.
This tutorial is divided into 7 parts:
- Introduction to SSL/TLS
- Confidentiality and integrity in TLS
- Basics of authentication in TLS (aka. TLS/SSL certificates)
- Domain validation vs Extended Validation
- Step-by-step instructions on how to create certificates on Linux
- Intermediate certificates
- Basic constraints
- Wrap up and useful links
Introduction to SSL/TLS
SSL (Secure Socket Layer) is an old protocol deprecated in favor of TLS (Transport Layer Security).
TLS is a protocol for the secure transmission of data based on SSLv3. It offers confidentiality, integrity, and authentication. In layman’s terms this means:
- Confidentiality: hides the content of the messages
- Integrity: detects when the messages have been tampered with
- Authentication: ensures that whoever is sending them is who he says he is.
Additionally, it detects missing and duplicated messages.
TLS is the primary way to secure web traffic and is mostly used for that purpose. A whole lot of pages trust that TLS is secure (from the smallest online shop to Facebook), that is why things like POODLE and Heartbleed receive so much press.
Confidentiality and integrity in TLS
I’ll briefly explain how TLS offers confidentiality and integrity. We will leave authentication at the end as that will be the bulk of the tutorial.
This section is here to make sure the tutorial covers all three bases (confidentiality, authentication, and integrity), so I will be using a lot of crypto jargon here. Do not fret if any of this seems alien to you, generally you won’t be fiddling with this directly as TLS negotiates much of this for you.
However, I do recommend getting familiar with the basics of public-key cryptography, not the inner workings mind you, just how they are used in practice to encrypt/authenticate.
If you are really interested in these subjects I’d recommend researching:
- Block ciphers modes of operation
- Cryptographic hashes
- Key exchange
- Public key cryptography
The Stanford Cryptography I in Coursera is an awesome starting point.
For confidentiality TLS uses AES with several modes available (CBC, CCM, GCM). For key exchange either Diffie-Hellman (elliptic curve mode supported) or RSA are available. With the whole Heartbleed debacle, it is now recommended to use a key exchange mechanism with forward secrecy, which implies Diffie-Hellman in this case.
For integrity HMAC is commonly used, today is pretty much mandatory to use SHA256.
Basics of authentication in TLS
Authentication is the part that you will most likely have to fiddle with the most and the one that actually costs you money, it is also essential for the security of your communications:
You. Cannot. Have. Secure. Communications. Without. Authentication.
Why is that you might ask? Well, the thing about confidentiality and integrity is that they are worthless without authentication. If there is no way to ensure that the guy that says “I am gmail.com I swear” is in fact gmail.com and not evil8yoldhacker.com, then you could potentially encrypt and validate a spurious connection.
So, without authentication you would be open to MitM (Man in the Middle) attacks for example. But how can you authenticate a server if you have never seen it before? and let alone exchanged any credentials with it?
The answer is TLS certificates. Certificates are just a public key with a bunch of information attached to it, such as the FQDN being authenticated, “issued on” and “expires on” dates, among other things. The server stores and keeps secret the corresponding private key. TLS uses these keys to authenticate the server to the client (a client can also use TLS to authenticate to a server, but we won’t cover that case here).
Recall that in public-key cryptography, messages encrypted with the public key can only be decrypted using the private key, but messages encrypted with the private key can be decrypted with either. The owner of the keys keeps the private key secret and distributes the public key freely:
Now, the usual way of authenticating someone using public-key cryptography is the following (Assume that Mallory wants to authenticate Alice):
- Mallory sends Alice a random message encrypted with Alice’s public key
- Alice decrypts the message using her private key and sends it back
- Mallory compares the message from Alice against the random one that he encrypted using Alice’s public key, if they match then Alice is who she says she is, because only her could have decrypted the random message, because only she has the corresponding private key.
Now, even with this trick validation of a certificate is not straightforward, so for didactic purposes we’ll begin with an oversimplified, naive, and flawed solution.
- A hash of the certificate is made, encrypted with the private key, and then appended to the certificate (recall that a certificate is just the corresponding public key with a bunch of metadata attached)
- The server sends the certificate to the clients that connect to it
- To verify the certificate the client decrypts the hash using the public key of the certificate, then calculates its own hash and compares them, if they are equal the certificate is valid
- It then sends a random message to the server encrypted with the provided public key, if the server sends the original unencrypted message back, then is considered authenticated
This process ensures that:
- The provided public key corresponds to the private key used to encrypt the hash of the certificate
- The server has access to the private key
The encrypted hash created appended to the certificate is called a digital signature. In this example, the server has digitally signed its own certificate, this is called a self-signed certificate.
Now, this scheme does not authenticate at all if you think about it. If an attacker manages to intercept the communications or divert the traffic, it can replace the public key on the certificate with his own, redo the digital signature with his own private key, and feed that to the client.
The problem lies in the fact that all the information necessary for verification is provided by the server, so the only thing you can be sure of is that the party that you’re talking to has the private key corresponding to the public key that it itself provided.
This is why when you connect to an entity with a self-signed certificate browsers will give a warning, they cannot ensure that whoever you are communicating with is who they say they are.
However, these kinds of certificates are very useful in some scenarios. They can be created free of charge, quickly and with little hassle. Thus they are good for some internal communications and prototyping.
So that did not work out. How can we solve it? Well, since the problem is that the server provides all the information for authenticating the certificate, why don’t we just move some of that information to the client?
Let us drive over to the client after lunch with a copy of the certificate in a USB drive, and store it directly on the client. Later when the server sends its certificate:
- The client decrypts the encrypted hash of the certificate (the digital signature) with the public key of the copy of the certificate that was provided earlier in the USB drive
- It then generates its own hash of the certificate and compares it to the decrypted version. This way it ensures that the certificate has not been tampered with
- It then sends a random message to the server encrypted with the public key. If the server sends back the original unencrypted message we consider it authenticated
If someone intercepts or diverts the connection, they have no hope of passing our random number challenge and providing a valid certificate, without the private key that is computationally infeasible.
The “driving over to the client after lunch with a USB drive” is called an out of band process.
Now this solution actually authenticates, and is sometimes used for internal communications. However it is not very practical for several use cases. It would be cumbersome to have to download a certificate every time you need to access a new secure website like a bank or eshop, or worse, waiting for someone to drive over to your house after lunch with a USB drive.
Moreover, if we were to download the certificate over the network, you’d have to ensure that the certificate is not tampered with on the way, which is one of the problems TLS should be solving for us in the first place. There is also the problem of what to do when the certificate expires, or how to revoke it if the private key becomes compromised.
Well, we got something working, but it is not quite ready for use on the landing page of your online store yet. How can we solve it? Well, here is where the money comes in.
Meet Bob, he is a well-known member of the community, a truly and responsible fellow loyal to a fault, and he comes up with a business. He will create a self-signed certificate, and will give it freely to everybody using an out of band process (let’s say, during a neighborhood-wide free-of-charge barbecue), he will then charge you a fee to digitally sign your certificate using his private key.
See, up until this time every certificate was self-signed, this time it is Bob that will sign it, now we’re in a situation where:
- Everybody has the certificate that Bob so generously gave them
- Everybody just trusts Bob (who wouldn’t, he saves orphan puppies from fires in his spare time)
Therefore, anyone that has his certificate signed with Bob’s private key can have it authenticated by anyone that has Bob’s certificate (because Bob’s certificate has his public key).
Bob will make sure nobody impersonates anyone. If he receives an email from you saying that you want certain certificate signed for your company, Bob will go to your house personally and ensure that it is your certificate, that it is your company, and that you did send out that email…you can never be too careful with all these evil 8-year-old hackers.
When Bob’s certificate is about to expire he will make sure he gives you a new one.
If anyone wants to revoke his or her certificate they can just tell Bob to put it in his list of revoked certificates. When somebody tries to authenticate a certificate signed by Bob they will call him to check if that certificate hasn’t been revoked.
Well, this is how the real world kind of works, with a few major changes:
- Bob is a CA (Certification Authority) such as DigiCert, Sectigo, Symantec, IdenTrust, GoDaddy, GlobalSign, etc (and no, they don’t save puppies from fires, they also f!@# up really bad sometimes)
- The out of band process is not a barbeque. Their certificates already come bundled with your operating system and browser (check /etc/ssl/certs if you’re on Linux)
- The revocation mechanisms are called CRL and OCSP (which was supposed to supersede CRL). The whole certificate revocation system is kind of a mess right now (1, 2, 3, 4). Another system to check the validity of certificates that works in tandem with CRL/OCSP is Certificate Transparency (1, 2).
- You kind of HAVE to trust them
The process where a third party that both the server and the client trust signs the certificate of the server creates a chain of trust. With TLS, we create chains of trust using CAs as our third parties.
Note that your data will not have stronger or weaker encryption depending on how much you pay, all TLS connections use some form of AES, how strong depends on what the client and server are able and willing to handle/use. For example, many servers refuse to use SSLv3 since the whole POODLE scandal, some old clients do not support the newest encryption algorithms (looking at you IE), some servers have not been updated to use the newest encryption algorithms.
Now, you might wonder, if every certificate gives me equally strong encryption, integrity, and authentication, why are some more costly than others?
Well, CAs generally charge you more for certificates that will be used on several machines, so for example a certificate for *.talpor.com will cost more than one for www.talpor.com. However, what CAs really sell is not certificates, is trust.
Domain validation vs Extended Validation
You might remember the part where “Bob will make sure nobody impersonates anyone”. Well, depending on how hard the CA tries to do this, it will charge more or less. There are three tiers of certification. Domain Validation, Organization Validation, Extended Validation.
Domain Validation is the cheapest and most basic form of validation. The CA just tries to make sure that you have some kind of control over the domain that you are trying to get a certificate for. They take a few minutes to validate and setup.
A common way to do domain validation is as follows. Say that you want a certificate for alice.com. After providing all the necessary information to the CA to generate your certificate (more on that later), the CA will give you a list of emails in the domain associated with the certificate, for example:
You are to pick one where a confirmation email will be sent, and here is the catch, you have no say as to which emails appear in that list, so you better have access to at least one of those.
Other common methods involve asking you to create a specific DNS record for the domain, having a particular string being returned in by a particular URL via HTTP, etc.
These kinds of validations not only include the usual domain validation checks, but they also take further steps to ensure that the company asking for the certificate does exist, physically and legally. These checks can range from phone calls to signed letters from the CEO. Because of this, these kinds of certificates can take several days to come out.
When faced with an EV certificate, browsers have some visual queue (green most of the time) that makes the address bar look more trustworthy, such as the green bar of Internet Explorer, or the big green square with the name of the company of Chrome.
Step-by-step instructions on how to create certificates on Linux
Now armed with all this knowledge, you want to create your very own certificate for your puppies and cats hospital webpage, how you go about it? Well, here are a few instructions for Linux systems.
Creating certificates to be signed by a CA
The steps are as follows:
- Create a private key and a Certificate Signing Request (CSR)
- Send the CSR to the CA, keep your private key secret at all times, never ever share it with anyone, not even the CA
- Go through the validation process which will vary depending on the type of validation that you’re going for. You will receive a signed certificate at the end of the process
- Place the certificate inside your server
- Configure your application to use the new certificate. For Linux systems this usually means configuring Nginx/Apache2 to use the new certificate and private key
- Conquer the world/Go home for the day (optional)
We will just cover step 1, as the rest are outside the scope of this tutorial.
The CSR is just your public key bundled with a bunch of parameters such as the domain to be authenticated, the encryption algorithm of the key, a digital signature to prevent tampering, the company name, the country, city and state, etc. Sending a CSR to a CA is very much like asking a very specific autograph from them.
Notice that CAs may ignore many fields of the CSR (company name, country, etc) if your certificate will only be domain validated.
So, to create a private key and its CSR on Linux you can do:
openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.csr
- openssl: the commonly used program to do TLS related stuff in Linux
- req: openssl command to manage CSRs
- -nodes: don’t set a passphrase of the private key (private keys of TLS certificates may have passphrases)
- -newkey rsa:2048: create a new key, make it RSA with 2048 bits
- -keyout: where to write the new key
- -out: where to write the CSR
This command will prompt you for some information regarding the CSR, such as the domain (which is called “common name”), country, company, etc. If you are only doing domain validation you can leave them all blank except for the common name.
If you want something more script-friendly you can use the -subj flag:
openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.csr -subj “/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com”
If you need to create a CSR from an existing key you can use:
openssl req -new -key example.key -out example.csr
To create a private RSA key you can do:
openssl genrsa -out example.key 2048
Creating self-signed SSL/TLS certificates
To sign your own certificate you can either use an existing CSR and private key or just create one from scratch.
To create a self-signed certificate from scratch you can use this oneliner:
openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.crt -x509 -days 365
- -x509: write out a self-signed certificate instead of a CSR (The technical name for TLS/SSL certificates is X.509 certificates)
- -days: how long will the certificate be valid. For certificates made from September 2020 onwards most browsers do not accept certificates with a validity period spanning more than 13 months (1, 2, 3, 4)
This command will prompt you for some information, if you’re looking for something without interactivity look up the -subj flag.
To create a self-signed certificate using an existing CSR and private key you can do:
openssl x509 -req -in example.csr -signkey example.key -out example.crt -days 365
- x509: openssl command to manage X.509 certificates (aka TLS/SSL certificates)
- -in: the CSR
- -signkey: the private key
- -out: where to write the certificate
- -days: see the previous command
One thing that might baffle you at first is that CAs sometimes give you many certificates. There are practical reasons for this, but the bottom line is that one of those is your certificate, and another one is a root certificate that corresponds to a private key that signed one of the other certificates, which in turn corresponds to a private key that signed another one, and so on and so forth, forming a chain of trust that eventually signs your certificate.
These intermediate certificates are called, well, intermediate certificates (Hurra for imagination). What you have to do is simply concatenate the certificates in the correct order, beginning with the certificate for your domain, and ending with the root certificate.
To figure out the correct order check first if your CA provides instructions, or if they gave you an already bundled version of the certificates.
If not you can check the “Subject” and “Issuer” fields of each certificate. The “Subject” field contains an identifier of the entity associated with the certificate, the “Issuer” contains the identifier of the entity that signed it.
Certificates come encoded in base64, but the following command will decode them:
openssl x509 -in example.crt -text -noout
There are also tools to verify the validity of a certificate chain, check this.
At this point, now that you know that certificates can be chained, you might have come up with a genius plan:
- Get a very cheap certificate from a CA
- Locally create a certificate that would be very expensive if it were signed by a CA (like an EV certificate)
- Use the private key of the cheap certificate to sign the expensive certificate that you created locally
- Bring the greedy and evil CAs to their knees with your devious and genius stratagem
Well no, you cannot do that: certificates have a field that determines whether or not its private key can sign other certificates (Extensions -> Basic Constraints -> CA: FALSE), and you cannot change this field in the certificate that the CA gives your because it would ruin the signature (recall that the signature is a hash of the certificate contents encrypted with the private key of the CA).
Wrap up and useful links
That about does it. There are a few details and a plethora of information and subjects that are not covered here, but from a practical standpoint this encompasses the very basics.
I leave a list of useful links at the end. If you find an error, typo, or another useful link, hop on in the comments and let me know.
- You can use this TLS checker to test the quality of your TLS connections
- A case to push EV certificates as the defacto standard from DigiCert
- Interesting articles of how the expiration of root certificates wreaks havoc in smart TVs
- TLS is far more complex than what I described here (1, 2, 3, 4)
- There are a lot of nice SSL/TLS tutorials out there (1, 2, 3, 4)
- There are also many step by step instructions out there (1, 2, 3, 4)