Cryptographic Fundamentals

Key Pair (Public Key + Private Key)

The foundation of TLS. Generated together mathematically.

# Generate key pair
openssl genrsa -out private.key 2048
openssl rsa -in private.key -pubout -out public.key

What they do:

  • Encrypt with public key → Only private key can decrypt
  • Sign with private key → Anyone with public key can verify

Certificate (X.509)

A certificate = public key + identity information + signature from CA.

┌─────────────────────────────────────────────────────────────────┐
│ Certificate Contents                                            │
│                                                                 │
│   Subject: CN=api.example.com, O=MyCompany   ← Who this is      │
│   Issuer: CN=DigiCert CA                     ← Who signed it    │
│   Valid From: 2026-01-01                                        │
│   Valid To: 2027-01-01                                          │
│   Public Key: MIIBIjANBgkqhkiG9w0BAQEFA...   ← Embedded         │
│   Signature: a7f3b2c1d4e5f6...               ← CA's stamp       │
└─────────────────────────────────────────────────────────────────┘

Certificate is NOT secret - it contains public key and can be shared freely.


Certificate Authority (CA)

An entity with its own key pair, whose job is to sign other certificates.

┌─────────────────────────────────────────────────────────────────┐
│ Root CA Resources                                               │
│                                                                 │
│   CA Private Key (HIGHLY SECRET)                                │
│     - Used to sign certificates                                 │
│     - Stored in HSM (Hardware Security Module)                  │
│                                                                 │
│   CA Certificate (PUBLIC)                                       │
│     - Contains CA's public key                                  │
│     - Self-signed (Issuer = Subject for root CA)                │
│     - Distributed to everyone who needs to trust this CA        │
└─────────────────────────────────────────────────────────────────┘

AWS Private CA

┌─────────────────────────────────────────────────────────────────┐
│ AWS Private CA provides:                                        │
│                                                                 │
│   CA Private Key                                                │
│     - Stored in AWS-managed HSM                                 │
│     - You NEVER see this                                        │
│     - AWS uses it to sign certs on your behalf                  │
│                                                                 │
│   CA Certificate                                                │
│     - You CAN download this                                     │
│     - Put this in API Gateway truststore for mTLS               │
│                                                                 │
│   Service: Issue certificates signed by this CA                 │
│     - You submit CSR (Certificate Signing Request)              │
│     - AWS signs it with CA private key                          │
│     - You get back signed certificate                           │
└─────────────────────────────────────────────────────────────────┘

Client Certificate Creation Flow

Step 1: Client generates key pair
┌─────────────────┐
│ Client          │
│ private.key     │ ← Keep secret
│ public.key      │
└─────────────────┘

Step 2: Client creates CSR (Certificate Signing Request)
┌─────────────────────────────────────────────────────────────────┐
│ CSR contains:                                                   │
│   - Client's public key                                         │
│   - Identity info (CN=client.example.com)                       │
│   - Signed with client's private key (proves ownership)         │
└─────────────────────────────────────────────────────────────────┘

Step 3: CA signs the CSR
┌─────────────────┐         CSR          ┌─────────────────┐
│ Client          │ ───────────────────► │ CA              │
│                 │ ◄─────────────────── │ Signs with      │
│                 │    Certificate       │ CA private key  │
└─────────────────┘                      └─────────────────┘

Step 4: Client now has
┌─────────────────┐
│ private.key     │ ← Still secret
│ client.crt      │ ← Certificate (public key + CA signature)
└─────────────────┘

Why TLS is Needed

Without TLS, attackers can impersonate servers.

Attack Scenarios Without TLS

DNS Spoofing:

You type: bank.com
Attacker poisons DNS
DNS returns: 185.99.99.99 (attacker's server)
You connect to attacker thinking it's bank.com

Man-in-the-Middle (MITM):

┌─────────┐              ┌──────────┐              ┌────────┐
│ You     │ ── request ─►│ Attacker │ ── request ─►│ Server │
│         │ ◄─ response ─│          │ ◄─ response ─│        │
└─────────┘              └──────────┘              └────────┘

Attacker sees: passwords, credit cards, session cookies
Attacker can: modify responses, inject malware

Why Attackers Can’t Impersonate WITH TLS

To impersonate bank.com, attacker needs certificate that:

  1. Has CN/SAN = “bank.com”
  2. Is signed by a CA in client’s truststore

Option A: Self-signed certificate

  • Client checks: Is issuer in my truststore? → NO → CONNECTION REFUSED

Option B: Get real CA to sign

  • CA requires proof of domain ownership
  • Attacker can’t prove ownership → Request denied

Option C: Steal certificate

  • Certificate without private key is useless
  • Can’t complete TLS handshake without private key

Standard TLS Flow (Server Certificate Only)

Before TLS:
  Server has: private key + certificate (signed by public CA)
  Client has: truststore with public CA root certificates (pre-installed)

Client                                              Server
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  1. ClientHello                                   │
   │     - TLS version, cipher suites, client_random   │
   │     - SNI: api.example.com                        │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  2. ServerHello                                   │
   │     - Chosen TLS version, cipher suite            │
   │     - server_random                               │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  3. Server Certificate                            │
   │     - Server's certificate + chain                │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  4. ServerHelloDone                               │
   │                                                   │
   │  ┌─────────────────────────────────────────────┐  │
   │  │ Client validates server certificate:        │  │
   │  │ 1. Check not expired                        │  │
   │  │ 2. Check CN/SAN matches hostname            │  │
   │  │ 3. Build chain to root CA                   │  │
   │  │ 4. Verify root CA in truststore             │  │
   │  │ 5. Verify signatures in chain               │  │
   │  └─────────────────────────────────────────────┘  │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  5. ClientKeyExchange                             │
   │     - Pre-master secret (encrypted with           │
   │       server's public key)                        │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  6. ChangeCipherSpec + Finished                   │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  7. ChangeCipherSpec + Finished                   │
   │                                                   │
   │  ═══════════════════════════════════════════════  │
   │         TLS Session Established                   │
   │         All traffic now encrypted                 │
   │  ═══════════════════════════════════════════════  │

Certificate Chain Validation

Server sends:
┌─────────────────────────────────────────────────────────────────┐
│ Server Certificate                                              │
│   Subject: CN=api.example.com                                   │
│   Issuer: CN=DigiCert SHA2 Secure Server CA                     │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼ verify with issuer's public key
┌─────────────────────────────────────────────────────────────────┐
│ Intermediate Certificate                                        │
│   Subject: CN=DigiCert SHA2 Secure Server CA                    │
│   Issuer: CN=DigiCert Global Root CA                            │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼ verify with root's public key
┌─────────────────────────────────────────────────────────────────┐
│ Root Certificate (in client's truststore)                       │
│   Subject: CN=DigiCert Global Root CA                           │
│   Issuer: CN=DigiCert Global Root CA  ← Self-signed             │
└─────────────────────────────────────────────────────────────────┘

Session Key Derivation

Both sides have:
  - client_random
  - server_random  
  - pre_master_secret (client generated, server decrypted)

Both compute:
  master_secret = PRF(pre_master_secret, client_random, server_random)
  session_keys = PRF(master_secret, ...)

Result: Identical symmetric keys without sending them over network

What Standard TLS Proves

WhatHow
Server is who it claimsCertificate signed by trusted CA
Server owns certificateDecrypts pre-master secret with private key
Traffic encryptedSymmetric keys from handshake
Traffic not tamperedMAC on every message

Does NOT prove: Who the client is (any client can connect).


mTLS Flow (Mutual TLS)

Both sides prove identity. Used for service-to-service, B2B APIs, IoT.

Before mTLS:
  Server has: private key + certificate + truststore (client CAs)
  Client has: private key + certificate + truststore (server CAs)

Client                                              Server
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  1. ClientHello                                   │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  2. ServerHello                                   │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  3. Server Certificate                            │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  4. CertificateRequest        ◄── NEW in mTLS     │
   │     - "Send me YOUR certificate"                  │
   │     - Acceptable CA list                          │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  5. ServerHelloDone                               │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  6. Client Certificate        ◄── NEW in mTLS     │
   │     - Client's certificate + chain                │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  7. ClientKeyExchange                             │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  8. CertificateVerify         ◄── NEW in mTLS     │
   │     - Signature of handshake messages             │
   │     - Signed with CLIENT's private key            │
   │     - PROVES client owns the certificate          │
   │                                                   │
   │  ──────────────────────────────────────────────►  │
   │  9. ChangeCipherSpec + Finished                   │
   │                                                   │
   │  ┌─────────────────────────────────────────────┐  │
   │  │ Server validates client certificate:        │  │
   │  │ 1. Check not expired                        │  │
   │  │ 2. Build chain to CA in truststore          │  │
   │  │ 3. Verify CA signature                      │  │
   │  │ 4. Verify CertificateVerify signature       │  │
   │  │    → Proves client has private key          │  │
   │  └─────────────────────────────────────────────┘  │
   │                                                   │
   │  ◄──────────────────────────────────────────────  │
   │  10. ChangeCipherSpec + Finished                  │
   │                                                   │
   │  ═══════════════════════════════════════════════  │
   │         mTLS Session Established                  │
   │         Both sides verified                       │
   │  ═══════════════════════════════════════════════  │

The 3 New Messages in mTLS

CertificateRequest (Server → Client):

  • Server says: “I require client authentication”
  • Contains acceptable certificate types and trusted CA list

Client Certificate (Client → Server):

  • Client sends certificate (public information)
  • Not proof of ownership yet

CertificateVerify (Client → Server):

  • Client signs handshake hash with private key
  • Server verifies with public key from certificate
  • If valid → client proved ownership

Why CertificateVerify Proves Ownership

Private key and public key are mathematically linked:
- Only matching private key can produce valid signature
- Public key can verify but CANNOT create signatures

Server: "Here's random challenge"
Client: sign(challenge, private_key) = signature
Server: verify(signature, public_key) → valid?

If valid → client has the private key → identity confirmed

mTLS Failure Scenarios

Client cert signed by unknown CA:

Client cert issuer: "SomeOther CA"
Truststore contains: "MyCompany CA"
Result: TLS handshake fails - "unknown CA"

Client cert expired:

Valid To: 2025-12-31
Current: 2026-01-02
Result: TLS handshake fails - "certificate expired"

Client doesn’t have private key (stolen cert):

Attacker has certificate but not private key
CertificateVerify: Can't produce valid signature
Result: TLS handshake fails - "bad certificate"

mTLS in API Gateway

Configuration

ComponentWhat to specify
Custom DomainRequired - mTLS only works with custom domains
TruststoreS3 URI to PEM file with trusted CA certificates
Client CertificateCertificate signed by CA in truststore
Client Private KeyCorresponding private key (stays on client)

Truststore Contents

Can contain root CA or intermediate CA - whichever signed the client certs.

-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQsFAMDC
... (Your CA certificate)
-----END CERTIFICATE-----

curl with mTLS

curl https://api.example.com/data \
  --cert client.crt \      # Client certificate (sent to server)
  --key client.key \       # Private key (used locally, NOT sent)
  --cacert ca-bundle.crt   # CA certs to verify server

Important: The private key is NOT sent over the network. curl uses it locally to sign the CertificateVerify message. Only the signature is sent.


TLS vs mTLS Summary

AspectStandard TLSmTLS
Server proves identity
Client proves identity
Client needs certificateNoYes
Client needs private keyNoYes
Server needs truststoreNoYes
Use casePublic websitesService-to-service, B2B, IoT

What TLS Protects Against

AttackWithout TLSWith TLS
DNS spoofingAttacker impersonates serverFake cert rejected
MITM on networkTraffic visible/modifiableEncrypted
BGP hijackingTraffic goes to attackerCan’t complete handshake
EavesdroppingPlaintext readableEncrypted
Traffic modificationCan inject/modifyMAC detects tampering