The CloudFlare guys make excellent technical posts. Recently they introduced Keyless SSL (which is a way of conducting the SSL protocol wherein the server you are talking to does not necessarily need to have the private key) and as part of the post going into its technical details they talk about the SSL protocol in general. Below are my notes on this and a few other posts. Crypto intrigues me as I like encryption and privacy so this is an area of interest.
Note: This is not a summary of the CloudFlare blog post. It was inspired by that post but I talk about a lot more basic stuff below.
The TLS/SSL protocol
First things first – what we refer to as Secure Sockets Layer (SSL) protocol is not really SSL but Transport Layer Security (TLS).
- Versions 1.0 to 3.0 of SSL were called, well … SSL 1.0 to SSL 3.0.
- TLS 1.0 was the upgrade from SSL 3.0. It is very similar to SSL such that TLS 1.0 is often referred to as SSL 3.1.
- Although the differences between TLS 1.0 and SSL 3.0 are not huge, the two cannot talk to each other. TLS 1.0, however, includes a mode wherein it can talk to SSL 3.0 but this decreases security.
The world still refers to TLS as SSL but keep in mind it’s really TLS. TLS has three versions so far – TLS 1.0, TLS 1.1, and TLS 1.2. A fourth version, TLS 1.3, is currently in draft form. I would be lying if I said I know the differences between these versions (or even the differences between SSL 3.0 and TLS 1.0) so it’s best to check the RFCs for more info!
The TLS/SSL protocol has two goals:
- Authenticate the two parties that are talking with each other (authentication of a server is the more common scenario – such as when you visit your bank’s website for instance – but authentication of the user/ client too is supported and used in some scenarios).
- Protect the conversation between the two parties.
Both goals are achieved via encryption.
Encryption is a way of “locking” data such that only a person who has a “key” to unlock it can read it. Encryption mechanisms are essentially algorithms: you take a message, follow the steps of the algorithm, and end up with an encrypted gobbledygook. All encryption algorithms make use of keys to lock and unlock the message – either a single key (which both encrypts and decrypts the message) or two keys (either can encrypt and decrypt).
Shared key encryption/ Symmetric encryption
A very simple encryption algorithm is the Caesar Cipher where all you do is take some text and replace the letters with letters that are a specified number away from it (for example you could replace “A” with “B”, “B” with “C”, and so on or “A” with “C”, “B” with “D”, and so on … in the first case you replace with a letter one away from it, in the second case you replace with a letter two away from it). For the Caesar Cipher the key is simply the “number of letters” away that you choose. Thus for instance, if both parties decide to use a key of 5, the encrypting algorithm will replace each letter with one that’s 5 letters away, while the decrypting algorithm will replace each letter with one that’s 5 letters before. The key in this case is a shared key – both parties need to know it beforehand.
Encryption algorithms where a single shared key is used are known as symmetric encryption algorithms. The operations are symmetrical – you do something to encrypt, and you undo that something to decrypt. TLS/SSL uses symmetric encryption to protect the conversation between two parties. Examples of the symmetric encryption algorithms TLS/SSL uses are AES (preferred), Triple DES, and RC4 (not preferred). Examples of popular symmetric algorithms can be found on this Wikipedia page.
Symmetric encryption has the obvious disadvantage that you need a way of securely sharing the key beforehand, which may not always be practical (and if you can securely share the key then why not securely share your message too?).
Public key encryption/ Asymmetric encryption
Encryption algorithms that use two keys are known as asymmetric encryption or public key encryption. The name is because such algorithms make use of two keys – one of which is secret/ private and the other is public/ known to all. Here the operations aren’t symmetrical- you do something to encrypt, and you do something else to decrypt. The two keys are special in that they are mathematically linked and anything that’s encrypted by one of the keys can be decrypted only by the second key. A popular public key encryption algorithm is RSA. This CloudFlare blog post on Elliptic Curve Cryptography (ECC), which is itself an example of a public key encryption algorithm, has a good explanation of how RSA works.
Public key encryption can be used for encryption as well as authentication. Say there are two parties, each party will keep its private key to itself and publish the public key. If the first party wants to encrypt a message for the second party, it can encrypt it using the public key of the second party. Only the second party will be able to decrypt the message as only it holds the private key. Thus the second party is authenticated as only the second party holds the private key corresponding to the public key.
Public key cryptography algorithms can also be used to generate digital signatures. If the first party wants to send a message to the second party and sign it, such that the second party can be sure it came from the first party, all the first party needs to do is send the message as usual but this time take a hash of the message encrypt that with its private key. When the second party receives this message it can decrypt the hash via the public key of the first party, make a hash itself of the message, and compare the two. If the hashes match it proves that the message wasn’t tampered in progress and also that the first party has indeed signed it as only its private key locked message can be unlocked by the public key. Very cool stuff actually!
Not all public key cryptography algorithms are good at encryption and signing nor are they required to be so. RSA, for instance, is good at encryption & decryption. Another algorithm, DSA (Digital Signature Algorithm) is good at signing & validation. RSA can do signing & validation too but that’s due to the nature of its algorithm.
A question of trust
While public key encryption can be used for authentication there is a problem. What happens if a third party publishes its public key on the network but claims that it is the second party. Obviously it’s a fraud but how is the first party to know of that? Two ways really: one way is the first party can perhaps call or through some other means verify with the second party as to what its public key is and thus choose the correct one – this is tricky because it has to verify the identity somehow and be sure about it – or, the second way, there can be some trusted authority that verifies this for everyone – such a trusted authority will confirm that such and such public key really belongs to the second party.
These two ways of finding if you can trust someone are called the Web of Trust (WoT) and Public Key Infrastructure (PKI) respectively. Both achieve the same thing, the difference being the former is decentralized while the latter is centralized. Both of these make use of something called certificates – which is basically a digital document that contains the public key as well as some information on the owner of the public key (details such as the email address, web address, how long the certificate is valid for, etc).
Web of Trust (WoT)
In a WoT model everyone uploads their certificates to certain public servers. When a first party searches for certificates belonging to a second party it can find them – both legitimate ones (i.e. actually belonging to the second party) as well as illegitimate ones (i.e. falsely uploaded by other parties claiming to the be second party). By default though the first party doesn’t trust these certificates. It only trusts a certificate once it verifies through some other means as to which is the legitimate one – maybe it calls up the second party or meets the party in person or gets details from its website. The first party can also trust a certificate if someone else it already trusts has marked a certificate as trusted. Thus each party in effect builds up a web of certificates – it trusts a few and it trusts whatever is trusted by the few that it trusts.
To add to the pool once a party trusts a certificate it can indicate so for others to see. This is done by signing the certificate (which is similar to the signing process I mentioned earlier). So if the first party has somehow verified that a certificate it found really belongs to the second party, it can sign it and upload that information to the public servers. Anyone else then searching for certificates of the second party will come across the true certificate too and find the signature of the first party.
WoT is what you use with programs such as PGP and GnuPG.
Public Key Infrastructure (PKI)
In a PKI model there are designated Certificate Authorities (CA) which are trusted by everyone. Each party sends their certificates to the CA to get it signed. The CA verifies that the party is who it claims to be and then signs it. There are many classes of validation – domain validation (the CA verifies that the requester can manage the domain the certificate is for), organization validation (the CA also verifies that the requester actually exists), and extended validation (a much more comprehensive validation than the other two).
Certificate Authorities have a tree structure. There are certain CAs – called root CAs – which are implicitly trusted by everyone. Their certificates are self-signed or unsigned but trusted by everyone. These root CAs sign certificates of other CAs who in-turn might sign certificates of other CAs or of a requester. Thus there’s a chain of trust – a root CA trust an intermediary CA, who trusts another intermediary CA, who trusts (signs) the certificate of a party. Because of this chain of trust, anyone who trusts the root CA will trust the certificate signed by one of its intermediaries.
It’s probably worth pointing out that you don’t really need to get your certificate signed by a CA. For instance, say I want to encrypt all traffic between my computer and this blog and so I create a certificate for the blog. I will be the only person using this – all my regular visitors will visit the blog unencrypted. In such a case I don’t have to bother with them not trusting my certificate. I trust my certificate as I know what its public key and details look like, so I can install the certificate and use an https link when browsing the blog, everyone else can use the regular http link. I don’t need to get it signed by a CA for my single person use. It’s only if I want the general public to trust the certificate that I must involve a CA.
PKI is what you use with Internet Browsers such as Firefox, Chrome, etc. PKI is also what you use with email programs such as Outlook, Thunderbird, etc to encrypt communication with a server (these emails program may also use WoT to encrypt communication between a sender & recipient).
From here on I’ll use the words “client” and “server” interchangeably with “first party” and “second party”. The intent is the same, just that it’s easier to think of one of one party as the client and the other as a server.
TLS/SSL uses both asymmetric and symmetric encryption. TLS/SSL clients use asymmetric encryption to authenticate the server (and vice-versa too if required) and as part of that authentication they also share with each other a symmetric encryption key which they’ll use to encrypt the rest of their conversation. TLS/SSL uses both types of encryption algorithms because asymmetric encryption is computationally expensive (by design) and so it is not practical to encrypt the entire conversation using asymmetric encryption (see this StackExchange answer for more reasons). Better to use use asymmetric encryption to authenticate and bootstrap symmetric encryption.
When a TLS/SSL client contacts a TLS/SSL the server sends the client its certificate. The client validates it using the PKI. Assuming the validation succeeds, client and server perform a “handshake” (a series of steps) the end result of which is (1) authentication and (2) the establishment of a “session key” which is the symmetric key used for encrypting the rest of the conversation.
CloudFlare’s blog post on Keyless SSL goes into more details of the handshake. There are two types of handshakes possible: RSA handshakes and Diffie-Hellman handshakes. The two types of handshakes differ in terms of what algorithms are used for authentication and what algorithms are used for session key generation.
RSA handshakes are based on the RSA algorithm which I mentioned earlier under public key encryption.
An RSA handshake uses RSA certificates for authentication (RSA certificates contain a public RSA key). Once authentication is successful, the client creates a random session key and encrypts with the public key of the server (this encryption uses the RSA algorithm). The server can decrypt this session key with its private key, and going forward both client & server use this session key to encrypt further traffic (this encryption does not use the RSA algorithm, it uses one of the symmetric key algorithms).
The RSA handshake has a drawback in that if someone were to capture and store past encrypted traffic, and if the server’s private key were to somehow leak, then such a person could easily decrypt the session key and thus decrypt the past traffic. The server’s private key plays a very crucial role here as it not only authenticates the server, it also protects the session key.
Diffie-Hellman handshakes are based on the Diffie-Hellman key exchange algorithm.
The Diffie-Hellman key exchange is an interesting algorithm. It doesn’t do any encryption or authentication by itself. Instead, it offers a way for two parties to generate a shared key in public (i.e. anyone can snoop in on the conversation that takes place to generate the secret key) but the shared key is secret and only the two parties know of it (i.e. the third party snooping in on the conversation can’t deduce the shared key). A good explanation of how Diffie-Hellman does this can be found in this blog post. Essentially: (1) the two parties agree upon a large prime number and a smaller number in public, (2) each party then picks a secret number (the private key) for itself and calculates another number (the public key) based on this secret number, the prime number, and the smaller number, (3) the public keys are shared to each other and using each others public key, the prime number, and the small number, each party can calculate the (same) shared key. The beauty of the math involved in this algorithm is that even though a snooper knows the prime number, the small number, and the two public keys, it still cannot deduce the private keys or the shared key!
There are two versions of the Diffie-Hellman algorithm:
- a fixed/ static version, where both parties use the same public/ private keys (and hence same shared key) across all their conversations; and
- an ephemeral version, where one party keeps changing its public/ private key (and hence the shared key)
Since the Diffie-Hellman algorithm does not do authentication it needs some other mechanism to authenticate the client and server. It can use an RSA certificate (certificates containing an RSA public key) or a non-RSA certificates – for example DSA certificates (certificates containing a DSA public key) and ECDSA (Elliptic Curve Digital Signature Algorithm) certificates (ECDSA is a variant of DSA that uses Elliptic Curve Cryptography (ECC). ECDSA certificates contain an ECC public key. ECC keys are better than RSA & DSA keys in that the ECC algorithm is harder to break. So not only are ECC keys more future proof, you can also use smaller length keys (for instance a 256-bit ECC key is as secure as a 3248-bit RSA key) and hence the certificates are of a smaller size).
The fixed/ static version of Diffie-Hellman requires a Diffie-Hellman certificate for authentication (see here and here). Along with the public key of the server, this certificate also contains the prime number and smaller number required by the Diffie-Hellman algorithm. Since these numbers are a part of the certificate itself and cannot change, Diffie-Hellman certificates only work with fixed/ static Diffie-Hellman algorithms and vice-versa. A Diffie-Hellman handshake that uses the fixed/ static Diffie-Hellman algorithm has the same drawback as a RSA handshake. If the server’s private key is leaked, past traffic can be decrypted.
The ephemeral version of Diffie-Hellman (often referred to as EDH (Ephermeral Diffie-Hellman) or DHE (Diffie-Hellman Ephemeral)) works with RSA certificates, DSA certificates, and ECDSA certificates. EDH/ DEH is computationally expensive as it is not easy to keep generating a new prime number and small number for every connection. A variant of EDH/ DEH that uses elliptic curves – known as Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) – doesn’t have the performance hit of EDH/ DEH and is preferred.
A Diffie-Hellman handshake that uses EDH/ DEH or ECDHE doesn’t have the drawback of an RSA handshake. The server’s private key is only used to authenticate it, not for generating/ protecting the shared session key. This feature of EDH/DHE and ECDHE wherein the shared keys are generated for each connection and are shared keys themselves are random and independent of each other is known as Perfect Forward Secrecy (PFS). (Perfect Forward Secrecy is a stronger form of Forward Secrecy. The latter does not require the shared keys themselves be independent of each other, only that the shared keys not be related to the server’s private/ public key).
To be continued …
Writing this post took longer than I expected so I’ll conclude here. I wanted to explore TLS/SSL in the context of Windows and Active Directory, but I got side-tracked talking about handshakes and RSA, ECDHE, etc. Am glad I went down that route though. I was aware of elliptic curves and ECDHE, ECDSA etc. but had never really explored them in detail until now nor written down a cumulative understanding of it all.