TLS/SSL — Certificates & Handshake
TLS (Transport Layer Security) encrypts communication between client and server. SSL is the deprecated predecessor — when people say "SSL" they usually mean TLS. HTTPS = HTTP over TLS.
TLS Handshake (TLS 1.3)
TLS 1.3 reduced the handshake to 1 RTT (vs 2 RTT in TLS 1.2). It also supports 0-RTT resumption for repeat connections.
Client Server
| |
|--- ClientHello --------------->| (supported ciphersuites, TLS version, random)
| |
|<-- ServerHello ----------------| (chosen ciphersuite, random)
|<-- Certificate ----------------| (server's cert + chain)
|<-- CertificateVerify ----------| (signature proving server owns the cert's private key)
|<-- Finished -------------------| (MAC of handshake)
| |
|--- Finished ------------------>| (client confirms)
| |
|=== Encrypted data exchange ====|
Total: 1 RTT (TLS 1.2 needed 2 RTTs)Certificates — Chain of Trust
Root CA: self-signed, trusted by OS/browser (e.g., DigiCert, Let's Encrypt ISRG Root)
Intermediate CA: signed by Root CA, signs leaf certificates. Allows Root to stay offline.
Leaf certificate: your domain's certificate, signed by Intermediate CA
fullchain.pem (Let's Encrypt): leaf + intermediates in one file — always use this in server config
privkey.pem: your private key — never share, keep secure, used to prove cert ownership
Certificate Types
DV (Domain Validated): just proves you control the domain. Automated, instant, free (Let's Encrypt). Shows padlock icon.
OV (Organization Validated): CA verifies your organization exists. Shows org name in cert details.
EV (Extended Validation): stricter verification, green bar in older browsers. Largely obsolete — Chrome removed visual distinction.
Wildcard (*.example.com): covers all first-level subdomains. Cannot be issued by Let's Encrypt automatically (requires DNS challenge).
SAN (Subject Alternative Names): one cert covers multiple domains. Let's Encrypt supports up to 100 SANs per cert.
Let's Encrypt & Certbot
# HTTP-01 challenge (requires port 80 accessible)
sudo certbot certonly --webroot \
--webroot-path /var/www/html \
-d example.com -d www.example.com
# DNS-01 challenge (for wildcards, works without public server)
sudo certbot certonly --manual --preferred-challenges dns \
-d "*.example.com" -d example.com
# Certbot prompts you to create a TXT record: _acme-challenge.example.com
# Standalone mode (certbot runs its own HTTP server on port 80)
sudo certbot certonly --standalone -d example.com
# Auto-renew test
sudo certbot renew --dry-run
# Certificate files location
ls /etc/letsencrypt/live/example.com/
# cert.pem — leaf certificate only
# chain.pem — intermediate chain only
# fullchain.pem — cert + chain (use in server config)
# privkey.pem — private keyOpenSSL — Certificate Inspection
# View certificate details from file
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout
# Check live server's certificate
openssl s_client -connect example.com:443 -servername example.com
# Check expiry date
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -enddate
# Verify certificate chain
openssl verify -CAfile chain.pem cert.pem
# Generate CSR (Certificate Signing Request) for a paid cert
openssl req -new -newkey rsa:2048 -nodes \
-keyout example.com.key \
-out example.com.csr \
-subj "/C=UA/ST=Kyiv/L=Kyiv/O=MyCompany/CN=example.com"
# Test TLS config
curl -I https://example.com --verbose 2>&1 | grep -E "SSL|TLS|certificate|issuer"
# Check which TLS versions are supported
nmap --script ssl-enum-ciphers -p 443 example.commTLS (Mutual TLS)
In mTLS, both client and server present certificates. The server verifies the client's certificate. Used for service-to-service communication, API security without passwords, and IoT device authentication.
# Generate CA, server, and client certs for mTLS
# 1. Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt -subj "/CN=My CA"
# 2. Server cert signed by CA
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com"
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -out server.crt
# 3. Client cert signed by CA
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=my-service"
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -out client.crt
# Test mTLS connection
curl https://api.example.com \
--cert client.crt \
--key client.key \
--cacert ca.crtKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free