We all are familiar with the terms SSL/TLS.
Technically, TLS is the successor to SSL, and SSL itself is now deprecated.
When we search about TLS, most blogs simplify it by saying that TLS converts HTTP into HTTPS.
To achieve this, they explain a handshake that goes something
like: “hello,” “hi,” “hello hi done” and now everything is encrypted.
But TLS is far more than that.
Let me explain.
First we need to understand what is CA (certificate authority)
A certificate authority (CA) is a trusted organization that issues digital certificates to websites, businesses, and individuals.
There are many popular CAs (Certificate Authorities) such as Let’s Encrypt, FreeSSL, etc.
Stage 1 — OS ships with pre-trusted CA certs
Before you install any browser, before you visit any website your OS already has ~130 trusted Certificate Authority (CA) public keys stored on disk. These are placed there by OS during installation.
On Ubuntu, you can check this using:
sudo cat /etc/ssl/certs/ca-certificates.crt
Each block is one CA’s self-signed certificate, it contains that CA’s public key and identity, the OS distro decided to include them.
Take one block and try to extract the details and it looks like:
Click to open
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6828503384748696800 (0x5ec3b7a6437fa4e0)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN = ACCVRAIZ1, OU = PKIACCV, O = ACCV, C = ES
Validity
Not Before: May 5 09:37:37 2011 GMT
Not After : Dec 31 09:37:37 2030 GMT
Subject: CN = ACCVRAIZ1, OU = PKIACCV, O = ACCV, C = ES
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:9b:a9:ab:bf:61:4a:97:af:2f:97:66:9a:74:5f:
d0:d9:96:fd:cf:e2:e4:66:ef:1f:1f:47:33:c2:44:
a3:df:9a:de:1f:b5:54:dd:15:7c:69:35:11:6f:bb:
c8:0c:8e:6a:18:1e:d8:8f:d9:16:bc:10:48:36:5c:
f0:63:b3:90:5a:5c:24:37:d7:a3:d6:cb:09:71:b9:
f1:01:72:84:b0:7d:db:4d:80:cd:fc:d3:6f:c9:f8:
da:b6:0e:82:d2:45:85:a8:1b:68:a8:3d:e8:f4:44:
6c:bd:a1:c2:cb:03:be:8c:3e:13:00:84:df:4a:48:
c0:e3:22:0a:e8:e9:37:a7:18:4c:b1:09:0d:23:56:
7f:04:4d:d9:17:84:18:a5:c8:da:40:94:73:eb:ce:
0e:57:3c:03:81:3a:9d:0a:a1:57:43:69:ac:57:6d:
79:90:78:e5:b5:b4:3b:d8:bc:4c:8d:28:a1:a7:a3:
a7:ba:02:4e:25:d1:2a:ae:ed:ae:03:22:b8:6b:20:
0f:30:28:54:95:7f:e0:ee:ce:0a:66:9d:d1:40:2d:
6e:22:af:9d:1a:c1:05:19:d2:6f:c0:f2:9f:f8:7b:
b3:02:42:fb:50:a9:1d:2d:93:0f:23:ab:c6:c1:0f:
92:ff:d0:a2:15:f5:53:09:71:1c:ff:45:13:84:e6:
26:5e:f8:e0:88:1c:0a:fc:16:b6:a8:73:06:b8:f0:
63:84:02:a0:c6:5a:ec:e7:74:df:70:ae:a3:83:25:
ea:d6:c7:97:87:93:a7:c6:8a:8a:33:97:60:37:10:
3e:97:3e:6e:29:15:d6:a1:0f:d1:88:2c:12:9f:6f:
aa:a4:c6:42:eb:41:a2:e3:95:43:d3:01:85:6d:8e:
bb:3b:f3:23:36:c7:fe:3b:e0:a1:25:07:48:ab:c9:
89:74:ff:08:8f:80:bf:c0:96:65:f3:ee:ec:4b:68:
bd:9d:88:c3:31:b3:40:f1:e8:cf:f6:38:bb:9c:e4:
d1:7f:d4:e5:58:9b:7c:fa:d4:f3:0e:9b:75:91:e4:
ba:52:2e:19:7e:d1:f5:cd:5a:19:fc:ba:06:f6:fb:
52:a8:4b:99:04:dd:f8:f9:b4:8b:50:a3:4e:62:89:
f0:87:24:fa:83:42:c1:87:fa:d5:2d:29:2a:5a:71:
7a:64:6a:d7:27:60:63:0d:db:ce:49:f5:8d:1f:90:
89:32:17:f8:73:43:b8:d2:5a:93:86:61:d6:e1:75:
0a:ea:79:66:76:88:4f:71:eb:04:25:d6:0a:5a:7a:
93:e5:b9:4b:17:40:0f:b1:b6:b9:f5:de:4f:dc:e0:
b3:ac:3b:11:70:60:84:4a:43:6e:99:20:c0:29:71:
0a:c0:65
Exponent: 65537 (0x10001)
X509v3 extensions:
Authority Information Access:
CA Issuers - URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1.crt
OCSP - URI:http://ocsp.accv.es
X509v3 Subject Key Identifier:
D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Authority Key Identifier:
D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD
X509v3 Certificate Policies:
Policy: X509v3 Any Policy
User Notice:
Explicit Text:
CPS: http://www.accv.es/legislacion_c.htm
X509v3 CRL Distribution Points:
Full Name:
URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1_der.crl
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Subject Alternative Name:
email:accv@accv.es
Signature Algorithm: sha1WithRSAEncryption
Signature Value:
97:31:02:9f:e7:fd:43:67:48:44:14:e4:29:87:ed:4c:28:66:
d0:8f:35:da:4d:61:b7:4a:97:4d:b5:db:90:e0:05:2e:0e:c6:
79:d0:f2:97:69:0f:bd:04:47:d9:be:db:b5:29:da:9b:d9:ae:
a9:99:d5:d3:3c:30:93:f5:8d:a1:a8:fc:06:8d:44:f4:ca:16:
95:7c:33:dc:62:8b:a8:37:f8:27:d8:09:2d:1b:ef:c8:14:27:
20:a9:64:44:ff:2e:d6:75:aa:6c:4d:60:40:19:49:43:54:63:
da:e2:cc:ba:66:e5:4f:44:7a:5b:d9:6a:81:2b:40:d5:7f:f9:
01:27:58:2c:c8:ed:48:91:7c:3f:a6:00:cf:c4:29:73:11:36:
de:86:19:3e:9d:ee:19:8a:1b:d5:b0:ed:8e:3d:9c:2a:c0:0d:
d8:3d:66:e3:3c:0d:bd:d5:94:5c:e2:e2:a7:35:1b:04:00:f6:
3f:5a:8d:ea:43:bd:5f:89:1d:a9:c1:b0:cc:99:e2:4d:00:0a:
da:c9:27:5b:e7:13:90:5c:e4:f5:33:a2:55:6d:dc:e0:09:4d:
2f:b1:26:5b:27:75:00:09:c4:62:77:29:08:5f:9e:59:ac:b6:
7e:ad:9f:54:30:22:03:c1:1e:71:64:fe:f9:38:0a:96:18:dd:
02:14:ac:23:cb:06:1c:1e:a4:7d:8d:0d:de:27:41:e8:ad:da:
15:b7:b0:23:dd:2b:a8:d3:da:25:87:ed:e8:55:44:4d:88:f4:
36:7e:84:9a:78:ac:f7:0e:56:49:0e:d6:33:25:d6:84:50:42:
6c:20:12:1d:2a:d5:be:bc:f2:70:81:a4:70:60:be:05:b5:9b:
9e:04:44:be:61:23:ac:e9:a5:24:8c:11:80:94:5a:a2:a2:b9:
49:d2:c1:dc:d1:a7:ed:31:11:2c:9e:19:a6:ee:e1:55:e1:c0:
ea:cf:0d:84:e4:17:b7:a2:7c:a5:de:55:25:06:ee:cc:c0:87:
5c:40:da:cc:95:3f:55:e0:35:c7:b8:84:be:b4:5d:cd:7a:83:
01:72:ee:87:e6:5f:1d:ae:b5:85:c6:26:df:e6:c1:9a:e9:1e:
02:47:9f:2a:a8:6d:a9:5b:cf:ec:45:77:7f:98:27:9a:32:5d:
2a:e3:84:ee:c5:98:66:2f:96:20:1d:dd:d8:c3:27:d7:b0:f9:
fe:d9:7d:cd:d0:9f:8f:0b:14:58:51:9f:2f:8b:c3:38:2d:de:
e8:8f:d6:8d:87:a4:f5:56:43:16:99:2c:f4:a4:56:b4:34:b8:
61:37:c9:c2:58:80:1b:a0:97:a1:fc:59:8d:e9:11:f6:d1:0f:
4b:55:34:46:2a:8b:86:3b
Stage 2 — You open Browser and visit blog.arjunshaji.me
Browser connects to the server on port 443. During the TLS handshake, the server sends its certificate as raw bytes no CA is contacted at this point. The cert just travels over the wire.
Browser → blog.arjunshaji.me:443
Client Hello → “I want TLS, here are cipher suites I support”
Server Hello ← “OK, let’s use TLS 1.3 + AES-256”
Certificate ← server sends the cert bytes
The certificate is just a file created and signed by the Certificate Authority (CA), not by the server itself. The CA signs the certificate using its private key, which allows browsers to verify its authenticity using the CA’s public key. During the TLS handshake, the server simply sends this certificate to every client that connects, and the browser stores the raw certificate bytes in memory for verification.
Note:
When we generate an SSL certificate technically a TLS certificate, but we still casually call it SSL.
The process creates a public/private key pair on the server, and the server communicates with the CA.
We commonly use tools like Certbot to generate certificates, but technically Certbot is just a client application that communicates between our server and the CA.
There are mainly three types of certificate validation:
- DV (Domain Validation) → The CA only checks: Do you control this domain?
- OV (Organization Validation) → The CA checks: Do you control the domain, and is your organization legally registered?
- EV (Extended Validation) → The CA performs the deepest verification, including legal existence, physical address, phone verification, and authorization checks.
For OV and EV certificates, human involvement is usually required. We typically generate and upload a CSR (Certificate Signing Request) to the CA portal.
The CA then verifies ownership, often by asking us to add a TXT record (usually used for verification) at the domain level.
After other verification, we can download the signed certificate manually, install it on the server, and configure it.
In the case of DV certificates, only domain-level validation is required, so human involvement is usually unnecessary.
Clients such as Certbot communicate with the CA using a protocol called ACME (Automatic Certificate Management Environment).
Technically, this communication happens through APIs. Once the ACME client (Certbot) is installed and configured on the server, the CSR generation, domain validation, certificate signing, renewal, and certificate installation can all happen automatically through API-based communication.
On Ubuntu, you can check the logs using:
sudo cat /var/log/letsencrypt/letsencrypt.log
Stage 3 — Browser reads the Issuer field to find the right CA
The certificate says who signed it inside the Issuer field. Browser uses this name to look up the correct CA public key from the OS trust store. This is how it picks 1 from 130+ CAs.
cert.Issuer = “CN=DigiCert TLS RSA SHA256 2020 CA1”
Eg: Broswer now opens /etc/ssl/certs/ca-certificates.crt
for each CA in trust store:
if CA.Subject == cert.Issuer:
found it! use this CA's public key
Stage 4 — The actual crypto verification (pure local math)
Browser now does two operations and compares the results.
No network. No CA. Just math using the CA public key it found in stage 3.
hash_A = SHA256(cert body) = a3f8bc…
hash_B = decrypt(signature,CA_public_key) = a3f8bc…
hash_A = a3f8bc… = hash_B = a3f8bc…
If hashes match CA definitely signed this cert (only they have the private key).
If they don’t match cert was tampered then the connection rejected immediately.
Stage 5 — Additional local checks
- Domain matches?
- Not expired?
etc …
Stage 6 — Key exchange and session key generation
After the certificate is verified, TLS performs a key exchange process to securely generate shared session keys.
TLS 1.3 supports three basic key exchange modes:
(Ref: https://datatracker.ietf.org/doc/html/rfc8446#section-2)
- (EC)DHE (Diffie-Hellman over either finite fields or elliptic
curves) - PSK-only
- PSK with (EC)DHE
The client and server exchange temporary public keys during the handshake and independently derive the same shared secret mathematically which are used for all encrypted communication between the client and server during the session.
The detailed cryptographic mathematics behind session key derivation is intentionally not covered in this article.
Stage 7 — What you see in Browsers’s padlock
All checks passed. Broswer shows the green padlock. When you click it ‘Connection is secure’, ‘Certificate is valid’ you are literally reading the same certificate that went through all the above steps.