Skip to content

PKI, Certificates & Cryptography in Practice

This note covers the applied side of cryptography: how public-key infrastructure works, how TLS/SSL actually secures a connection, how SSH authenticates, and the hardware that underpins system trust.


PKI is the system of people, processes, and technology that manages public key cryptography at scale. The core problem: how do you trust that a public key really belongs to who they claim?

The Trust Problem:
Alice wants to talk to "Bob's Bank".
She receives a public key - but how does she know it's really the bank's key
and not an attacker's key? She needs a TRUSTED THIRD PARTY to vouch.
→ That's what a Certificate Authority does.
ComponentRole
Certificate Authority (CA)Issues, signs, and revokes digital certificates
Registration Authority (RA)Verifies identity of entities requesting certificates
Certificate RepositorySecure, indexed storage for issued certificates
Certificate Revocation List (CRL)List of certificates that have been invalidated before expiry
OCSP (Online Certificate Status Protocol)Real-time certificate validity check (alternative to CRL)
End-entity / Leaf CertificateThe certificate presented to clients (e.g., your HTTPS cert)
Root CA (self-signed, offline, stored in OS/browser trust store)
└── Intermediate CA (signed by Root CA)
└── End-entity certificate (signed by Intermediate CA, presented to user)
  • Root CAs are self-signed - their trustworthiness is bootstrapped by being pre-installed in your OS or browser (via OS vendors like Apple/Microsoft/Mozilla)
  • Intermediate CAs separate the Root (kept offline) from day-to-day signing operations - limits exposure of the root private key
  • Leaf certificates are what websites, servers, and clients present
Terminal window
# Inspect full certificate chain of a domain
openssl s_client -connect google.com:443 -showcerts 2>/dev/null | \
openssl x509 -noout -text | grep -A2 "Issuer\|Subject\|Validity"
# Or show the chain visually
openssl s_client -connect google.com:443 2>/dev/null | \
sed -n '/-----BEGIN/,/-----END/p' | \
openssl x509 -noout -subject -issuer

X.509 is the standard format for digital certificates (first published 1988, now on v3). Every HTTPS certificate, code signing certificate, and S/MIME email cert follows this format.

FieldContentsExample
VersionX.509 version (always v3 now)3
Serial NumberUnique ID assigned by the CA4A:B1:2C:...
Signature AlgorithmHow the CA signed the certsha256WithRSAEncryption
IssuerCA that issued this certCN=Let's Encrypt R3, O=Let's Encrypt
ValidityNot Before / Not After dates2024-01-01 to 2025-01-01
SubjectWho the cert is issued TOCN=example.com
Subject Public Key InfoThe public key + algorithmEC, P-256
Subject Alternative Names (SANs)Additional hostnames this cert coversexample.com, www.example.com
Certificate Signature ValueCA’s digital signature over all fields(binary)
Terminal window
# View full certificate details
openssl x509 -in certificate.crt -text -noout
# Check just validity dates
openssl x509 -in certificate.crt -noout -dates
# Check Common Name and SANs
openssl x509 -in certificate.crt -noout -subject -ext subjectAltName
# Verify certificate against a CA bundle
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt certificate.crt
TypePurposeWho Validates
DV (Domain Validation)Proves you control the domainAutomated DNS/HTTP challenge
OV (Organization Validation)Proves domain + legal org identityCA manually verifies org docs
EV (Extended Validation)Strict org identityIntensive CA vetting
WildcardCovers *.example.comDV or OV
Client certificateAuthenticates a client to a serverPrivate CA typically
Code signing certSigns executables/packagesCA + may require OV

Certificates can be invalidated before they expire (key compromise, org change):

Terminal window
# Check if a cert is revoked via OCSP
openssl ocsp \
-issuer issuer.crt \
-cert site.crt \
-url http://ocsp.example.com \
-resp_text

PGP and GPG use a decentralised web of trust instead of a central CA hierarchy:

  • Individuals sign each other’s public keys after verifying identity in person
  • Trust is transitive: if you trust Alice, and Alice signed Bob’s key, you can transitively trust Bob
  • No single authority - but also no revocation infrastructure, and trust is hard to bootstrap
Terminal window
# Generate a GPG key pair
gpg --full-generate-key
# Export your public key to share
gpg --armor --export [email protected] > pubkey.asc
# Sign someone else's key (after verifying their identity)
gpg --sign-key [email protected]
# Encrypt a file for a recipient
gpg --encrypt --recipient [email protected] file.txt
# Sign a file
gpg --detach-sign --armor file.txt # produces file.txt.asc

TLS (Transport Layer Security) is what makes HTTPS work. It provides:

  • Confidentiality - data is encrypted
  • Integrity - data cannot be modified without detection
  • Authentication - server proves its identity via certificate
Client Server
│── ClientHello ──────────────────→│
│ (supported cipher suites, │
│ key share, TLS version) │
│ │
│←── ServerHello + Certificate ───│
│ (chosen cipher, server's │
│ public key share, │
│ certificate) │
│ │
│── [verify cert against CA] ── │
│── [derive session keys via ECDH]─│
│ │
│── Finished (encrypted) ─────────→│
│←── Finished (encrypted) ────────│
│ │
│══ Encrypted application data ═══│

Key improvements in TLS 1.3 vs 1.2:

  • 1-RTT handshake (vs 2-RTT) = faster connection setup
  • 0-RTT resumption for returning connections (with replay attack caveats)
  • Forward secrecy is mandatory (ECDHE only - no static RSA key exchange)
  • Eliminated weak cipher suites (RC4, 3DES, MD5, SHA-1)

Even if the server’s private key is stolen years later, past sessions remain private because session keys are ephemeral (ECDHE - generated fresh for each session, then discarded).

Terminal window
# Test what TLS versions and ciphers a server supports
openssl s_client -connect example.com:443 -tls1_3
# Full TLS inspection with nmap
nmap --script ssl-enum-ciphers -p 443 example.com
# Check if a server supports TLS 1.0/1.1 (should not)
openssl s_client -connect example.com:443 -tls1

SSH provides encrypted remote access to command-line systems. It uses the same public-key cryptography principles as TLS but in a different protocol.

Authentication Methods (in order of security)

Section titled “Authentication Methods (in order of security)”
MethodHow it worksWhen to use
Key-basedClient holds private key; server has public key in ~/.ssh/authorized_keysAlways prefer this
Certificate-basedSSH CA signs user/host keys; eliminates managing individual authorized_keysLarge scale deployments
PasswordUsername + password over encrypted channelDisable in production
NoneNo authenticationNever
Terminal window
# Generate Ed25519 key pair (preferred - fast, secure, small)
ssh-keygen -t ed25519 -C "[email protected]"
# Generate RSA key (for compatibility with older systems)
ssh-keygen -t rsa -b 4096 -C "[email protected]"
# Copy public key to a remote server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
# Manually add public key to authorised_keys
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Terminal window
# /etc/ssh/sshd_config - key settings
Port 2222 # Non-default port (minor obscurity)
PermitRootLogin no # Never allow root login
PasswordAuthentication no # Key-only auth
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
LoginGraceTime 20
AllowUsers alice bob # Allowlist specific users
ClientAliveInterval 300 # Disconnect idle sessions after 5m
ClientAliveCountMax 2
# Restart after changes
sudo systemctl restart sshd
Terminal window
# Verify no password auth is possible
ssh -o PasswordAuthentication=yes user@host
# should fail: "Permission denied (publickey)"

A dedicated secure chip soldered to the motherboard. Provides:

FunctionWhat it does
Secure key generationGenerates truly random keys inside tamper-resistant hardware
Hardware attestationProves to remote systems that the hardware+software configuration is unmodified
Data bindingEncrypts data to this specific TPM - migrating to another device fails to decrypt
Data sealingEncrypts data AND locks it to a specific system state (e.g., only decrypts if Secure Boot passed)
Full Disk EncryptionBitLocker (Windows), systemd-cryptenroll (Linux) use TPM to auto-unlock FDE
Terminal window
# Check if TPM 2.0 is present and active (Linux)
ls /dev/tpm* # device nodes
tpm2-tools tpm2_getcap properties-fixed
# Enrol TPM for LUKS disk encryption (systemd)
systemd-cryptenroll --tpm2-device=auto /dev/sda3
Disk layout with FDE:
┌─────────────────────────────────────────────────────────────┐
│ /boot (UNENCRYPTED) │
│ kernel, bootloader, initramfs │
├─────────────────────────────────────────────────────────────┤
│ / root volume (ENCRYPTED - AES-256-XTS) │
│ OS, user data, everything else │
│ Unlocks at boot via: │
│ - TPM (auto, if PCR values match) │
│ - Passphrase (manual entry) │
│ - Recovery key (stored offline) │
└─────────────────────────────────────────────────────────────┘

FDE tools:

PlatformToolUnderlying Crypto
Linuxdm-crypt / LUKSAES-256-XTS
macOSFileVault 2AES-128-XTS
WindowsBitLockerAES-128 or AES-256-XTS
Cross-platformVeraCryptAES, Serpent, Twofish
Terminal window
# Set up LUKS encryption on a partition (Linux)
cryptsetup luksFormat /dev/sdb1 # initialise LUKS
cryptsetup open /dev/sdb1 secure_data # unlock to /dev/mapper/secure_data
mkfs.ext4 /dev/mapper/secure_data # create filesystem
mount /dev/mapper/secure_data /mnt/secure # mount
# Add a second passphrase (recovery key) to LUKS
cryptsetup luksAddKey /dev/sdb1

Cryptography lives or dies by randomness. Predictable “random” numbers → predictable keys → broken encryption.

SourceDescriptionUse case
/dev/urandomNon-blocking CSPRNG (Linux)General crypto; safe to use after boot
/dev/randomBlocks until entropy pool refilled (older kernel)Legacy - no advantage over urandom on Linux 5.6+
RDRAND (CPU)Intel/AMD hardware RNG instructionFeeds entropy pool; fast
TPM RNGHardware RNG from TPM chipHigh-assurance keys
Terminal window
# Generate 32 bytes of cryptographically secure random data
dd if=/dev/urandom bs=32 count=1 | base64
# Or using openssl
openssl rand -base64 32
# Check entropy pool size (Linux)
cat /proc/sys/kernel/random/entropy_avail

Useful for internal services, dev environments, or lab setups.

Terminal window
# 1. Create root CA key and self-signed certificate
openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1826 \
-out rootCA.crt \
-subj "/C=US/O=MyOrg CA/CN=MyOrg Root CA"
# 2. Generate server key and CSR (Certificate Signing Request)
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/C=US/O=MyOrg/CN=internal.myorg.com"
# 3. Sign the server certificate with the root CA
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key \
-CAcreateserial -out server.crt -days 365 -sha256 \
-extfile <(printf "subjectAltName=DNS:internal.myorg.com,DNS:localhost")
# 4. Verify the chain
openssl verify -CAfile rootCA.crt server.crt
# 5. Trust the root CA system-wide (Ubuntu/Debian)
sudo cp rootCA.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates