Learn It In 15 Minutes with Hands-On Exercises
The first question to get out of the way: is there any difference between SSL and TLS?
No. SSL is the original name, which stands for Secure Sockets Layer. TLS is newer, and it stands for Transport Layer Security.
In real life, people say SSL. Yet they mean TLS.
Understanding Cryptography First?
It would help, but not enough to make it necessary. I’d recommend skipping it, at least for now. Focus on the basics here.
TLS relies on asymmetrical encryption. The math behind the inner workings is interesting if you want to dive deeper into math. You can grok TLS fine without knowing why asymmetric encryption works.
Time for some hands-on work.
OpenSSL is a command-line utility. It enables you to make keys and certificates as well as inspect them and verify their contents.
Several versions exist. Plus there are different builds for different operating systems.
- For Windows, go here: OpenSSL for Windows
- For macOS, use homebrew, like this.
- And, OpenSSL is native to Linux. Official download here.
If you have the technical know-how, install a Linux VM on your computer and use OpenSSL in there. And if I said things that make no sense to you, no worries. Skip it. You’re fine to use OpenSSL on whatever operating system you have right now.
It’s a command-line utility. Open a command-line window (or terminal) on your machine.
To verify you’ve got it installed, type OpenSSL version and press enter. You’ll see want you’ve got installed.
Two Purposes of TLS
There are two reasons why two machines talking via a network should be using TLS.
- Security of the data transmitted between them
- Proof of who they are
In some cases, you only need to be using one of the features. For example, you might only need data encryption over the network. I’ll give some concrete examples.
Let’s say you are starting an online store. You’ll be accepting credit card payments. Your website needs to receive that data encrypted. This will prevent a man-in-the-middle attack. Nothing is transmitted in plaintext.
Also, you also want the browser on the customer’s computer to trust your website is who it says it is. That way the browser won’t show security warnings and scare your customers away.
In this case, you want both encryption and verification of server identity.
And here’s a case where you don’t care about verification. Let’s say you are setting up a person FTP server.
You want to do FTP over TLS. Otherwise, your password will go in plaintext over the internet. Not cool.
But at the same time, it’s not a critical project. You’re doing it for fun. So server verification isn’t important to you.
In this case, the encryption of data between computers only interests you.
Speaking of the computers encrypting the data now is a good time to talk about the handshake.
That’s what it’s called when two computers set up a TLS connection with each other. Here’s how it goes down.
The client sends the version of TLS it wants to use and a list of ciphers it knows. The server responds with the selected cipher and certificate for inspection/verification.
Want to dig deeper? This is one of the best resources I’ve seen explaining byte-by-byte the whole process.
https://tls.ulfheim.net/ (screenshot below)
How Can I Trust You?
The root of all trust is in the CA or certificate authority. For websites, you need to use an established CA that browsers trust.
But if you are making an intranet site or something else that is internal, you can be your own CA.
That could be confusing, so let’s break it down.
All certificate authority certificates are self-signed. That is, no one else vouches for them. Meaning, no one other certificate digitally signs their cert.
Browsers know who they trust.
Who they trust can change. CAs have been distrusted due to bad practices. In that case, anyone who bought a certificate from them and used it on their website wasted their money. Their website will show up as insecure when visited.
If it’s an internal project, IT has control of all the machines. So, the company can create a CA cert itself and install the cert as a trusted cert on each machine.
The CA cert will often sign an intermediary cert, and that will be used to sign the cert for a given website.
The CA’s job is vetting the owner of the website before issuing a cert that is signed by their CA root cert. That’s where the trust comes from.
Look at this screenshot to see the trust flow from the website’s certificate back to the trusted CA.
Your Turn To Be A Certificate Authority
Remember, all CA root certs are self-signed. You can be your own CA for practice.
Pretend you are working on an IoT device. That’s a perfect application for your own CA cert.
Step one is to create a private key for signing the root CA cert.
Anyone who gets this key can sign a cert as if they were you. Lose this key, and your trust is worthless.
In the command-line, use this command
openssl genrsa -aes256 -out rootCA.key 4096
The breakdown of the command is as follows:
- openssl tells your computer to use the OpenSSL program
- genrsa specifics to OpenSSL that you want to generate an RSA key, which is a long string essentially
- -aes256 tells OpenSSL that you want to encrypt the key with a password using aes256 as the encryption. It’s best practice to always use a password on a key as an extra layer of security
- -out rootCA.key tells OpenSSL that you want it to make a file called rootCA.key. And that it should save the encrypted private key string in that file
- 4096 is the number of bytes to make the key. The longer this is, the stronger the key is. Think of the private key as a sort of password. Longer passwords are harder to guess. And longer keys are stronger. A common number is 2048. Longer is better, but it puts a greater strain on the server.
After making the private key, if you open it in a text editor, this is what it looks like.
Now you create the CA root cert and sign it with your rootCA.key.
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt
The breakdown of the command is as follows:
- openssl (you already know what this does)
- req specifies you are making a request
- -x509 tells it you’re making a certificate
- -new does what you’d expect as it tells it you are asking for a new item (x509 cert in this case)
- -nodes means “no des” or do not encrypt the result of this command
- -key rootCA.key tells it what private key is used for the signing of this cert
- -sha256 tells it what hashing algorithm to use
- -days 1024 tells it how long to make the cert valid for (3650 days or 10 years in this case)
- -out rootCA.crt tells it what file to output the certificate into
After making the self-signed CA cert, if you open it in a text editor, this is what it looks like.
Signing Your Certificates
To recap, you’ve created a key and used that to create the CA cert.
Now we’ll use the CA certificate to generate any server certificate you need. Here’s how it’s done.
Step one is to create a certificate signing request, also called a CSR. To sign the CSR, you need to create a private key for it (don’t confuse this private key with the CA root private key).
Run this command.
openssl genrsa -aes256 -out example-com.com.key 2048
Then run this.
openssl req -new -key example-com.key -out example-com.csr
OpenSSL will ask you several questions. Only one is critical. It’s the common name. It has to match exactly the server name you’re going to use the cert on. You can skip the email address and challenge password.
Let’s say you are going to use the certificate on a server with the IP address 18.104.22.168, and that’s how you intend to address it.
Then the common name is that IP address: 22.214.171.124.
If you are making a cert for https://example.com, then the common name is example.com.
One more example. If you have a website that has many subdomains, and you want one cert to cover them all, you can use a wildcard.
In this case, your common name would be *.example.com. That’s what I did in the screenshot.
I have one more edge case to share before moving on. The wildcard example will cover any subdomain.
But say you only want to cover a specific set of subdomains. In that case, you’d use a SAN certificate. SAN stands for subject alternative name.
The OpenSSL command to make a CSR for a SAN cert is a bit more complex.
openssl req -new -sha256 -key example-com.key -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=mydomain.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:mydomain.com,DNS:www.mydomain.com")) -out mydomain.com.csr
That’s a complex command for sure. You’ll notice its doing the inputs inline. Plus, it’s using config file to feed in the domain whitelist.
Okay, before continuing, I always like to verify my CSR’s information before generating the cert from it. To do that, use this command.
openssl req -in example-com.csr -noout -text
And finally you create the server certificate with the CSR and root key and certificate.
openssl x509 -req -in example-com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out example-com.crt -days 730 -sha256
Verifying Your Certificate
It’s impossible to verify a cert or key just by opening them in a text editor.
For verifying that they came out as I expected, here are two commands I use.
First, just to look at the cert contents:
openssl x509 -in example-com.crt -text -noout
Second, this is for verifying that your private key matches your CSR and your certificate.
openssl x509 -noout -modulus -in example-com.crt | openssl md5
openssl req -noout -modulus -in example-com.csr | openssl md5
openssl rsa -noout -modulus -in example-com.key | openssl md5
The output should match exactly.
Third, verify the server cert chains back to the root CA cert.
openssl verify -verbose -CAfile <(cat rootCA.crt) example-com.crt
You might be wondering why I did a cat command on the single rootCA.crt file.
You don’t need it yet, but I wanted to show you the proper way to check if there is an intermediate cert in the chain.
A quick example from Google.com
openssl verify -verbose -CAfile <(cat GTSCA1O1.crt GlobalSignRootCA-R2.crt) www_google_com.crt
The GTSCA1O1.crt is the intermediate cert that Google.com is using at the moment. GlobalSign is the certificate authority.
How To Get a Cert From a Real CA
When you buy a certificate for your website from a CA, you don’t do the actual cert creation.
It’s a bit simpler. The first several steps are the same.
You create a private key, and then you use that to create the CSR.
Next, you submit the CSR to the CA, and they generate your server cert for you.
You can still run the three verification steps:
- key/cert match
- looking at the cert’s contents.
If you feel a bit OCD about the process like me, you’ll do all the verification all the time. 🙂
Certificates Over on the Other Side (Client Certificates)
Up till now, all we’ve discussed have been server-side certificates.
In normal web browsing, that’s all you are interacting with. Your browser isn’t giving a certificate (as the client to the website you are visiting) to any server.
Sometimes the server needs to trust the client. For example, IoT devices often use client-side certificates.
Generating the client cert is very much like making a server cert. The main difference is that the common name isn’t very important. It doesn’t need to match anything on the client-side to be valid.
A best practice is to treat it like a username or identifier.
To make a client cert, start by making a private key. Then create a CSR with that key. Next, generate the cert with your CA cert and key.
openssl genrsa -aes256 -out client1.key 1024
openssl req -new -key client1.key -out client1.csr
openssl x509 -req -days 3650 -in client1.csr -CA rootCA.crt -CAkey rootCA.key -set_serial 123 -out client1.crt
Note that there is a new flag in the command -set_serial. Increment or randomize this for each client cert you create.
A best practice is to create a new cert for each device or client. That way you can invalidate a cert and disallow or revoke any one device.
The Alphabet Soup Of Certificate Formats
There are lots of file extensions, and they aren’t as clear in denoting the file contents as I’d prefer them to be.
For example, a key can be a PEM or KEY file. A certificate could be in DER format or PEM format in a CRT file.
The best explanation I’ve come across is from the crypto StackExchange site. Here’s a direct quote.
File extensions can be (very) loosely seen as a type system.
.pem stands for PEM, Privacy Enhanced Mail; it simply indicates a base64 encoding with header and footer lines. Mail traditionally only handles text, not binary which most cryptographic data is, so some kind of encoding is required to make the contents part of a mail message itself (rather than an encoded attachment). The contents of the PEM are detailed in the header and footer line – .pem itself doesn’t specify a data type – just like .xml and .html do not specify the contents of a file, they just specify a specific encoding
.key can be any kind of key, but usually it is the private key – OpenSSL can wrap private keys for all algorithms (RSA, DSA, EC) in a generic and standard PKCS#8 structure, but it also supports a separate ‘legacy’ structure for each algorithm, and both are still widely used even though the documentation has marked PKCS#8 as superior for almost 20 years; both can be stored as DER (binary) or PEM encoded, and both PEM and PKCS#8 DER can protect the key with password-based encryption or be left unencrypted;
.csr stands for Certificate Signing Request, it contains information such as the public key and common name required by a Certificate Authority to create and sign a certificate for the requester, the encoding could be PEM or DER (which is a binary encoding of an ASN.1 specified structure);
.crt stands simply for certificate, usually an X509v3 certificate, again the encoding could be PEM or DER; a certificate contains the public key, but it contains much more information (most importantly the signature by the Certificate Authority over the data and public key, of course).
Beware that not everyone may use the same extensions – there is no official register or anything like that. You’re probably better off using the POSIX file command-line utility first.
While that answer is quite good, it doesn’t mention a few file types like pfx and p7b. So, let’s discuss those to round out this part.
To recap, pem, crt, ca-bundle, cer, p7b and p7s files are all base64 encoded. Simply, they are text-based, and they will contain one or more certificates. If they contain more than one cert, the others will be the certs up the chain.
Then there are pfx files. A pfx will contain one or more certificates and a matching private key too, and it is not ASCII based. Also, a pfx file will usually be password protected.
Converting Between File Types
OpenSSL can convert from any certificate file type to another. Go here to see the options: https://knowledge.digicert.com/solution/SO26449.html
Did you do all the commands along with me?
You know TLS better than most software developers. So, congrats! It’s been fun sharing with you.