Introduction: The Cryptographic Web
Every time you see the padlock in your browser, TLS is at work. It's the foundation of web security—encrypting data, verifying server identity, and ensuring integrity of communication.
Series Context: This is Part 17 of 20 in the Complete Protocols Master series. TLS operates at the Presentation/Session layers, securing Application Layer protocols like HTTP, SMTP, and IMAP.
1
Part 1: OSI Model & Protocol Foundations
Network layers, encapsulation, TCP/IP model
2
Physical & Data Link Layers
Ethernet, Wi-Fi, VLANs, MAC addressing
3
Network Layer & IP
IPv4, IPv6, ICMP, routing protocols
4
Transport Layer
TCP, UDP, QUIC, ports, sockets
5
Session & Presentation Layers
TLS handshake, encryption, serialization
6
Web Protocols
HTTP/1.1, HTTP/2, HTTP/3, WebSockets
7
API Protocols
REST, GraphQL, gRPC, SOAP
8
DNS Deep Dive
DNS hierarchy, records, DNSSEC
9
Email Protocols
SMTP, IMAP, POP3, SPF/DKIM/DMARC
10
File Transfer Protocols
FTP, SFTP, SCP, rsync
11
Real-Time Protocols
WebRTC, SIP, RTP, VoIP
12
Streaming Protocols
HLS, DASH, RTMP, media delivery
13
IoT Protocols
MQTT, CoAP, Zigbee, LoRaWAN
14
VPN & Tunneling
IPsec, OpenVPN, WireGuard
15
Authentication Protocols
OAuth, SAML, OIDC, Kerberos
16
Network Management
SNMP, NetFlow, Syslog
17
Security Protocols
TLS/SSL, certificates, PKI
You Are Here
18
Cloud Provider Protocols
AWS, Azure, GCP APIs
19
Emerging Protocols
QUIC, HTTP/3, WebTransport
20
Web Security Standards
CORS, CSP, HSTS, SRI
Security Goals
What TLS Provides
TLS Security Properties:
1. CONFIDENTIALITY
• Data encrypted in transit
• Only sender/receiver can read
• Symmetric encryption (AES, ChaCha20)
2. INTEGRITY
• Data not modified in transit
• Detects tampering
• MAC or AEAD
3. AUTHENTICATION
• Server proves identity (always)
• Client proves identity (optional)
• X.509 certificates
What TLS Does NOT Provide:
• Privacy (metadata visible: IPs, timing)
• Protection at rest (only in-transit)
• Protection against compromised endpoints
History
SSL/TLS Evolution
| Version | Year | Status | Notes |
| SSL 2.0 | 1995 | ❌ Insecure | Broken |
| SSL 3.0 | 1996 | ❌ Insecure | POODLE attack |
| TLS 1.0 | 1999 | ❌ Deprecated | BEAST vulnerable |
| TLS 1.1 | 2006 | ❌ Deprecated | Weak ciphers |
| TLS 1.2 | 2008 | ✅ Acceptable | Still widely used |
| TLS 1.3 | 2018 | ✅ Recommended | Modern, faster |
TLS Protocol Deep-Dive
TLS 1.3 is a major improvement over 1.2—faster handshake (1-RTT), removed obsolete algorithms, and mandatory forward secrecy. Let's understand both.
TLS 1.2
TLS 1.2 Handshake
TLS 1.2 Full Handshake (2-RTT):
Client Server
| |
|--- ClientHello -----------------> |
| (version, random, cipher suites, |
| extensions) |
| |
|<-- ServerHello -------------------| |
|<-- Certificate -------------------| |
|<-- ServerKeyExchange -------------| |
|<-- ServerHelloDone ---------------| |
| |
|--- ClientKeyExchange ------------> |
|--- ChangeCipherSpec -------------> |
|--- Finished (encrypted) ---------> |
| |
|<-- ChangeCipherSpec --------------| |
|<-- Finished (encrypted) ----------| |
| |
[Application Data flows encrypted]
2 Round Trips before app data!
TLS 1.3
TLS 1.3 Handshake (1-RTT)
TLS 1.3 Handshake (1-RTT):
Client Server
| |
|--- ClientHello -----------------> |
| (supported versions, key_share, |
| cipher suites) |
| |
|<-- ServerHello -------------------| |
|<-- EncryptedExtensions -----------| |
|<-- Certificate -------------------| |
|<-- CertificateVerify -------------| |
|<-- Finished ----------------------| |
| |
|--- Finished ----------------------> |
| |
[Application Data flows encrypted]
Only 1 Round Trip!
TLS 1.3 also supports 0-RTT:
• Resumed connections send data immediately
• Trade-off: Replay attack possible
# Inspect TLS connection with OpenSSL
# Connect and show certificate
openssl s_client -connect example.com:443 -showcerts
# Check TLS version and cipher
openssl s_client -connect example.com:443 2>/dev/null | \
grep -E "Protocol|Cipher"
# Protocol : TLSv1.3
# Cipher : TLS_AES_256_GCM_SHA384
# Force specific TLS version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
# Show certificate details
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -text
# Check certificate expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# TLS connection inspection with Python
import ssl
import socket
from datetime import datetime
def inspect_tls(hostname, port=443):
"""Inspect TLS connection details"""
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as tls_sock:
print(f"TLS Connection to {hostname}")
print("=" * 50)
# Protocol version
print(f"Protocol: {tls_sock.version()}")
# Cipher suite
cipher = tls_sock.cipher()
print(f"Cipher: {cipher[0]}")
print(f"Bits: {cipher[2]}")
# Certificate
cert = tls_sock.getpeercert()
print(f"\nCertificate:")
print(f" Subject: {dict(x[0] for x in cert['subject'])}")
print(f" Issuer: {dict(x[0] for x in cert['issuer'])}")
# Validity
not_after = cert['notAfter']
expiry = datetime.strptime(not_after, '%b %d %H:%M:%S %Y %Z')
days_left = (expiry - datetime.now()).days
print(f" Expires: {not_after} ({days_left} days)")
# SANs
if 'subjectAltName' in cert:
sans = [x[1] for x in cert['subjectAltName']]
print(f" SANs: {', '.join(sans[:3])}...")
# Example
# inspect_tls('google.com')
print("""
TLS 1.3 Improvements:
• 1-RTT handshake (was 2-RTT)
• 0-RTT resumption (with replay risk)
• Forward secrecy mandatory
• Removed RSA key exchange
• Removed weak ciphers (RC4, 3DES)
• Simplified cipher suite naming
""")
X.509 Certificates
X.509 certificates are digital documents that bind a public key to an identity. They're the foundation of internet trust—your browser trusts thousands of root CAs.
Structure
Certificate Anatomy
X.509 Certificate Structure:
Certificate:
Version: 3 (0x2)
Serial Number: unique identifier
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=DigiCert Global Root CA, O=DigiCert Inc
Validity:
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Dec 31 23:59:59 2025 GMT
Subject: CN=example.com, O=Example Inc
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
X509v3 Extensions:
Basic Constraints: CA:FALSE
Key Usage: Digital Signature, Key Encipherment
Extended Key Usage: TLS Web Server Authentication
Subject Alternative Name:
DNS:example.com
DNS:www.example.com
Authority Key Identifier: ...
Certificate Policies: ...
CRL Distribution Points: ...
Authority Information Access:
OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://...
Signature Algorithm: sha256WithRSAEncryption
Signature: (binary signature)
# Certificate operations with OpenSSL
# Generate private key
openssl genrsa -out server.key 2048
# Generate CSR (Certificate Signing Request)
openssl req -new -key server.key -out server.csr \
-subj "/CN=example.com/O=Example Inc/C=US"
# Self-signed certificate (for testing)
openssl x509 -req -days 365 -in server.csr \
-signkey server.key -out server.crt
# View certificate
openssl x509 -in server.crt -noout -text
# Verify certificate chain
openssl verify -CAfile ca-bundle.crt server.crt
# Check certificate matches key
openssl x509 -noout -modulus -in server.crt | md5sum
openssl rsa -noout -modulus -in server.key | md5sum
# Should match!
# Convert formats
openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx
openssl pkcs12 -in server.pfx -out server.pem -nodes
# Certificate analysis with Python
from cryptography import x509
from cryptography.hazmat.backends import default_backend
import ssl
import socket
def analyze_certificate(hostname):
"""Analyze server certificate"""
# Get certificate
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as tls:
der_cert = tls.getpeercert(binary_form=True)
# Parse certificate
cert = x509.load_der_x509_certificate(der_cert, default_backend())
print(f"Certificate Analysis: {hostname}")
print("=" * 50)
# Subject
print(f"Subject: {cert.subject.rfc4514_string()}")
print(f"Issuer: {cert.issuer.rfc4514_string()}")
# Validity
print(f"Valid From: {cert.not_valid_before}")
print(f"Valid Until: {cert.not_valid_after}")
# Key info
pub_key = cert.public_key()
print(f"Key Type: {type(pub_key).__name__}")
print(f"Key Size: {pub_key.key_size} bits")
# SANs
try:
san = cert.extensions.get_extension_for_class(
x509.SubjectAlternativeName)
names = san.value.get_values_for_type(x509.DNSName)
print(f"SANs: {names}")
except x509.ExtensionNotFound:
print("SANs: None")
# Signature algorithm
print(f"Signature: {cert.signature_algorithm_oid._name}")
# Example
# analyze_certificate('google.com')
PKI Infrastructure
PKI (Public Key Infrastructure) is the trust hierarchy that makes certificates work. Root CAs are trusted by browsers, and they sign intermediate CAs, which sign end-entity certificates.
Chain of Trust: Your browser trusts ~150 root CAs. Each root can sign intermediates, which sign server certificates. If ANY CA is compromised, the whole system fails.
Trust Chain
Certificate Chain
Certificate Trust Chain:
Root CA Certificate (self-signed)
└── Trusted by browsers/OS
└── Stored offline, rarely used
|
↓ signs
Intermediate CA Certificate
└── Signs end-entity certificates
└── Limits blast radius if compromised
|
↓ signs
End-Entity Certificate (your server)
└── Presented to clients
└── Valid for specific domain(s)
Example Chain:
1. DigiCert Global Root CA (in browser trust store)
2. DigiCert SHA2 Extended Validation Server CA
3. www.example.com
Server sends: #3 + #2 (leaf + intermediates)
Browser has: #1 (root, pre-trusted)
# View certificate chain
# Show full chain
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
grep -E "s:|i:" | head -10
# Chain depth
# 0 s: CN=www.example.com (leaf)
# i: CN=DigiCert SHA2 Extended Validation Server CA (intermediate)
# 1 s: CN=DigiCert SHA2 Extended Validation Server CA
# i: CN=DigiCert High Assurance EV Root CA (root)
# Verify chain
openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt
Types
Certificate Types
| Type | Validation | Indicator | Use Case |
| DV | Domain only | Padlock | Personal sites |
| OV | Organization verified | Padlock | Business sites |
| EV | Extended validation | Padlock (was green bar) | E-commerce, banks |
| Wildcard | *.domain.com | Padlock | Multiple subdomains |
| Multi-domain | SAN list | Padlock | Multiple domains |
Cipher Suites
A cipher suite defines the algorithms used for key exchange, authentication, encryption, and integrity. TLS 1.3 simplified this significantly.
TLS 1.2
TLS 1.2 Cipher Suite Format
TLS 1.2 Cipher Suite:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Breakdown:
TLS_ Protocol
ECDHE_ Key Exchange (Elliptic Curve Diffie-Hellman Ephemeral)
RSA_ Authentication (RSA signature)
WITH_
AES_256_ Encryption (AES 256-bit)
GCM_ Mode (Galois/Counter Mode - AEAD)
SHA384 Hash for PRF (Pseudo-Random Function)
Key Exchange Options:
• RSA: Server's RSA key (NO forward secrecy!)
• DHE: Diffie-Hellman Ephemeral
• ECDHE: Elliptic Curve DHE (preferred)
Authentication:
• RSA: RSA signature
• ECDSA: Elliptic Curve Digital Signature
Encryption:
• AES-GCM: Modern, fast (AEAD)
• AES-CBC: Older, needs separate MAC
• ChaCha20-Poly1305: Mobile-friendly
TLS 1.3
TLS 1.3 Cipher Suites (Simplified)
TLS 1.3 Cipher Suites:
Only 5 cipher suites:
• TLS_AES_256_GCM_SHA384
• TLS_AES_128_GCM_SHA256
• TLS_CHACHA20_POLY1305_SHA256
• TLS_AES_128_CCM_SHA256
• TLS_AES_128_CCM_8_SHA256
Why simpler?
• Key exchange ALWAYS ephemeral (forward secrecy)
• Authentication separate (in certificate)
• Only AEAD ciphers allowed
TLS 1.3 removes:
• RSA key exchange (no forward secrecy)
• Static DH
• CBC mode ciphers
• RC4, 3DES, MD5, SHA-1
# Check server cipher suites
# List supported ciphers
nmap --script ssl-enum-ciphers -p 443 example.com
# Test specific cipher
openssl s_client -connect example.com:443 \
-cipher 'ECDHE-RSA-AES256-GCM-SHA384'
# Modern cipher configuration (nginx)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Mozilla SSL Configuration Generator
# https://ssl-config.mozilla.org/
Certificate Validation
When your browser receives a certificate, it performs multiple checks: chain validation, expiration, revocation, and domain matching.
Validation
Certificate Validation Steps
Certificate Validation Checks:
1. CHAIN VALIDATION
• Build path to trusted root
• Verify each signature
• Check BasicConstraints (CA:TRUE for intermediates)
2. VALIDITY PERIOD
• notBefore < now < notAfter
• Alert if expired or not yet valid
3. REVOCATION CHECK
• CRL (Certificate Revocation List)
• OCSP (Online Certificate Status Protocol)
• OCSP Stapling (server provides status)
4. NAME MATCHING
• CN or SAN must match hostname
• Wildcard matching rules (*.example.com)
5. KEY USAGE
• digitalSignature for TLS server auth
• Extended Key Usage: serverAuth
6. POLICY CHECK
• Certificate Transparency logs
• CAA DNS records
# Certificate revocation checks
# Check OCSP
openssl ocsp -issuer intermediate.crt -cert server.crt \
-url http://ocsp.digicert.com -resp_text
# Check CRL
openssl crl -in crl.pem -text -noout
# OCSP stapling test
openssl s_client -connect example.com:443 -status 2>/dev/null | \
grep -A 17 "OCSP Response"
# Certificate Transparency lookup
# https://crt.sh/?q=example.com
# Certificate validation in Python
import ssl
import socket
from datetime import datetime
def validate_certificate(hostname):
"""Validate server certificate"""
print(f"Validating certificate for {hostname}")
print("=" * 50)
# Create context with validation
context = ssl.create_default_context()
# context.check_hostname = True (default)
# context.verify_mode = ssl.CERT_REQUIRED (default)
try:
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as tls:
cert = tls.getpeercert()
print("✅ Chain valid (trusted by system CA store)")
print("✅ Hostname matches")
# Check expiration
not_after = cert['notAfter']
expiry = datetime.strptime(not_after, '%b %d %H:%M:%S %Y %Z')
days_left = (expiry - datetime.now()).days
if days_left > 0:
print(f"✅ Not expired ({days_left} days remaining)")
else:
print(f"❌ EXPIRED!")
return True
except ssl.SSLCertVerificationError as e:
print(f"❌ Validation failed: {e}")
return False
except ssl.CertificateError as e:
print(f"❌ Certificate error: {e}")
return False
# Test
# validate_certificate('google.com')
# validate_certificate('expired.badssl.com') # Will fail
Summary & Next Steps
Key Takeaways:
- TLS 1.3: 1-RTT handshake, mandatory forward secrecy
- X.509: Standard for digital certificates
- PKI: Root → Intermediate → End-Entity chain
- Cipher suites: Key exchange + Auth + Encryption
- Validation: Chain, expiry, revocation, hostname
Quiz
Test Your Knowledge
- TLS 1.3 vs 1.2 handshake? (1-RTT vs 2-RTT)
- What's forward secrecy? (Compromised key doesn't decrypt past traffic)
- Why intermediate CAs? (Limit blast radius, keep root offline)
- OCSP vs CRL? (Real-time check vs periodic list)
- Why no RSA key exchange in TLS 1.3? (No forward secrecy)