Digital Signatures

A digital signature proves three things: who sent a message, that the message hasn’t been altered, and that the sender cannot deny sending it. This is the cryptographic foundation beneath code signing, TLS certificates, and every verified git commit.

Mental Model: The Notarized Document

A handwritten signature on a contract proves the signer agreed to the terms. A digital signature does the same thing, but with a mathematical guarantee instead of a forensic one. The signer uses their private key to produce the signature; anyone with the corresponding public key can verify it. Unlike a handwritten signature, a digital signature is bound to the exact content — changing a single bit invalidates it.

This gives digital signatures a property that handwritten signatures lack: tamper detection. A forged modification to a signed document is mathematically detectable.

Signing Is Not Encrypting

A common misconception is that signing encrypts the message. It does not. A signed message is still plaintext — anyone can read it. What the signature provides is proof of origin and integrity. The signer hashes the message, then encrypts the hash with their private key. That encrypted hash is the signature. Verification decrypts the signature with the public key and compares the result to a fresh hash of the message. If they match, the signature is valid.

Non-Repudiation: What MACs Cannot Provide

MACs (from lesson 4) also prove integrity and authenticity. But MACs use a shared symmetric key — both parties can produce a valid MAC. If Alice and Bob share an HMAC key, and a message arrives with a valid MAC, either of them could have produced it. Neither can prove the other sent it. A third party cannot determine the author.

Digital signatures use asymmetric keys. Only the private key holder can produce the signature, but anyone with the public key can verify it. This is non-repudiation: the signer cannot credibly deny having signed, because no one else possesses their private key.

Why Non-Repudiation Matters in Practice

Non-repudiation is a legal and operational requirement, not just a theoretical property. Code signing proves which developer or organization published a binary. Signed audit logs prove which administrator performed an action. Signed financial transactions prove which party authorized a transfer. In each case, the system requires proof that can convince a third party — a court, an auditor, a compliance system. MACs cannot satisfy this requirement; digital signatures can.

Signature Algorithms: RSA, ECDSA, Ed25519

RSA signatures (PKCS#1 v1.5 and PSS): the signer hashes the message and encrypts the hash with their RSA private key. RSA-PSS (Probabilistic Signature Scheme) adds randomized padding, making it provably secure under standard assumptions. RSA signatures are large (256 bytes for a 2048-bit key) and slow to produce. Still widely deployed in legacy systems and X.509 certificates.

ECDSA: the elliptic curve analog of the older DSA scheme. Produces compact signatures (64 bytes for P-256) with faster operations than RSA. ECDSA is used in Bitcoin transaction signing, AWS IAM signing, and TLS certificates on NIST curves. One critical weakness: ECDSA requires a unique random nonce per signature. Nonce reuse leaks the private key — this is how Sony’s PlayStation 3 signing key was extracted in 2010.

Ed25519: deterministic signatures on Curve25519. No random nonce needed — the nonce is derived from the message and private key, eliminating the nonce-reuse vulnerability entirely. Signatures are 64 bytes, verification is fast, and the implementation is resistant to side-channel attacks by design. Ed25519 is the recommended choice for new systems.

Choosing a Signature Algorithm

Ed25519 is the default choice absent a specific constraint. A system that requires NIST-approved curves (government, compliance) uses ECDSA with P-256. RSA is reserved for interoperability with legacy systems that do not support elliptic curves. RSA should use PSS padding — not PKCS#1 v1.5, which has known vulnerabilities when verification is improperly implemented.

Certificate Chains and PKI

A digital signature proves the signer holds a private key. But how can it be known which public key belongs to which entity? This is the trust problem, and Public Key Infrastructure (PKI) solves it with a chain of signatures.

A certificate authority (CA) is a trusted entity that signs certificates. The chain works hierarchically: a root CA signs an intermediate CA’s certificate, and the intermediate CA signs a leaf certificate (the one a server uses). A browser trusts a set of root CAs — roughly 100-150 of them, preinstalled by the operating system. When a browser connects to a server, it walks the chain from the leaf certificate up to a trusted root, verifying each signature along the way.

Why Intermediate CAs Exist

Root CA private keys are extraordinarily valuable — compromise of a root key undermines trust in every certificate it has ever signed. Root keys are kept offline in hardware security modules, used only to sign intermediate CA certificates. The intermediate CAs handle day-to-day certificate issuance. If an intermediate CA is compromised, it can be revoked without replacing the root. This layered architecture limits the blast radius of a key compromise.

X.509 Certificates

An X.509 certificate is the standard format for public key certificates in TLS, code signing, and email encryption. It binds a public key to an identity (a domain name, an organization, an email address) and includes metadata: the issuer (who signed it), validity dates, permitted usages, and the signature itself.

Key fields: Subject (who the certificate identifies), Issuer (who signed it), Subject Alternative Name (additional identities, including domain names for TLS), Key Usage (what the key is authorized for — signing, encryption, certificate signing), Validity Period (not-before and not-after dates).

Running openssl x509 -text -noout -in cert.pem reads an X.509 certificate. A certificate issued by Let’s Encrypt is an X.509 certificate signed by Let’s Encrypt’s intermediate CA.

Certificate Revocation

Certificates have expiration dates, but sometimes a certificate must be invalidated before it expires — a private key compromise, a domain ownership change, a CA misbehaving. Two mechanisms exist: CRL (Certificate Revocation Lists) — a signed list of revoked serial numbers published by the CA — and OCSP (Online Certificate Status Protocol) — a real-time query to the CA asking if a specific certificate is still valid. In practice, browsers use OCSP stapling: the server fetches its own OCSP response and includes it in the TLS handshake, so the browser doesn’t need to contact the CA separately.

The Software Perspective

Git commit signing: git commit -S signs a commit with a GPG or SSH key. GitHub and GitLab display a “Verified” badge on signed commits. This proves the commit was made by the key holder, not just someone who set user.email in their git config. It is configured with git config commit.gpgsign true and git config gpg.format ssh for SSH-based signing.

Code signing: macOS Gatekeeper, Windows Authenticode, and Android APK signing all require binaries to carry a digital signature. The operating system verifies the signature before execution. Unsigned or invalidly signed code triggers security warnings or outright rejection.

JWT RS256 and ES256: JSON Web Tokens use RS256 (RSA-SHA256 signature) or ES256 (ECDSA with P-256 and SHA-256) for asymmetric verification. Unlike HS256 (HMAC), asymmetric JWT signatures let any party verify the token without possessing the signing key. This is essential for distributed systems where the token issuer and the token verifier are different services.

TLS certificates: every HTTPS connection begins with the server presenting its X.509 certificate. The browser verifies the signature chain, checks the domain name against the Subject Alternative Name, confirms the certificate hasn’t expired, and checks revocation status. Only then does the handshake proceed to key exchange.

Key Takeaways

This lesson establishes:

  • The sign-then-verify process: hash the message, sign the hash with the private key, verify by decrypting with the public key and comparing hashes
  • Non-repudiation and why MACs cannot provide it
  • How RSA signatures, ECDSA, and Ed25519 compare and which is preferred for new systems
  • How certificate chains establish trust from a leaf certificate to a root CA
  • The key fields in an X.509 certificate and their purpose

Next: The TLS Handshake

← Cryptography Fundamentals Digital Signatures