Distributing public keys is a way to enable authentication of machines.
Machine A sends a message to machine B, claiming the identity K_A, by
signing with k_A. B verifies that signature, hence the identity. But
this protocol requires B to know or to ascertain K_A. Until now,
we've just assumed there's a way for B to do that. Let's actually
solve the problem now.
### Digital Certificates
A *digital certificate* (henceforth, *certificate*) is a signature
Sign(id_S, K_S; k_I) on the pair of an identity id_S and public key
K_S of a subject S. A certificate is created by an *issuer* I, whose
signing key is k_I. The certificate binds id_S to K_S according to I.
As a simpler notation for this idea, let Cert(S; I) be a certificate
issued by I for S. Hence Cert(S; I) = Sign(id_S, K_S; k_I).
If machine A has acquired a certificate Cert(S; I), and if A trusts I to
issue that certificate, then A has a basis to verify S's identity.
**Authentication with Certificates**
1. S: Let m = "I'm id_S".
Compute s = Sign(m; k_S).
2. S -> A: m, s
3. A: Find a certificate Cert(S; I) from a trusted issuer I.
Verify the signature of I on the certificate.
Verify that the identifier in the certificate is id_S.
Retrieve K_S from the certificate.
Accept if Ver(m; s; K_S).
In step 1, m could contain additional information to be authenticated
beyond the identity of S. In step 3, one common implementation error is
to forget to verify id_S. Indeed, sometimes crypto libraries will not do
this for you by default.
The most common format for certificates is X.509, an
international standard. Beyond id_S, K_S, and the signature, an X.509
signature also contains a serial number, a validity interval, and
several other data.
### Public Key Infrastructure
The final step above requires verifying a signature on a certificate. If
A already knows I's public key, that's not a problem. But if not, it
seems like all we've done is to make a recursive call: to verify S's
key, A needs to verify I's key. And that might involve finding and
verifying even more certificates. Where does the recursion end? At
some point, A needs to reach a certificate issued by a principal that A
is willing to trust. To solve this problem, we need a system to help
mangage the distribution of certificates. Such systems are called *public key
infrastructures* (PKIs). There are two philosophies for building PKIs:
- **Decentralized:** anarchy, no publicly recognized leaders, e.g.,
- **Centralized:** oligarchy, leadership of a few elite, e.g., CAs
### PGP: Pretty Good Privacy
PGP, a program implementing encryption and digital
signature schemes, was invented by Phil Zimmerman in 1991. He made it
and source code publicly available. This was notable as the first time
there had been popular open source for public-key cryptography. The US Customs
Service launched a criminal investigation for violation of export laws.
High-strength cryptography was classified as a munition, so there was some
question that Zimmerman might have been guilty of arms trafficking.
After three years, the investigation was dropped.
The philosophy of PGP is decentralized. Management of certificates
devolves to users; anyone can certify anyone else and distribute that
certificate as they wish. With PGP, a user A accumulate certificates
that she trusts on a *keyring*. The user's own key is on that keyring as
a *self-signed* certificate Cert(A; A). From time to time, A might
synchronize with another user B, importing keys from B's keyring.
When a user acquires a certificate, she records how much trust to
place in the issuer, hence in the certificate. The result is a *web of
trust*: a user can have multiple certificates for a given key from
multiple issuers. There's no central repository of certificates that has
to be trusted. So there's also no central service that could be taken
down, DOS'd, coerced, seized by law enforcement, etc. Nonetheless, it's
convenient to have such servers, and they do exist.
[MIT runs one](https://pgp.mit.edu/), for example.
**Example.** *Suppose Bob sends Alice a message that he signs. Alice now
needs to verify the signature, and to do that, she needs a certificate
for Bob. She searches for certificates for Bob, and manages to find
Cert(Bob;Dave), Cert(Bob;Bob), and Cert(Bob;Carol). Alice doesn't happen
to know Dave, Bob, or Carol. So she searches around for certificates for
them. She manages to find a certificate Cert(Carol; Ellen), and realizes
that Ellen is a friend of her that she trusts, and that Ellen's public
key is already in her (Alice's) keyring, as Cert(Ellen;Alice). So Alice
has Cert(Alice; Alice), Cert(Ellen; Alice), Cert(Carol; Ellen),
Cert(Bob; Carol). After verifying all those certificates, Alice can
create a new certificate Cert(Bob; Alice), put it in her keyring, and
later distribute it to others. And, of course, she can verify Bob's
signature on the message.*
In the example above, Alice ends up with a list of certificates:
Cert(Alice; Alice), Cert(Ellen; Alice), Cert(Carol; Ellen), Cert(Bob;
Carol). This list forms a *certificate chain*, starting with a
certificate for Alice and ending with a certificate for Bob. At the
*root* is a key that Alice trusts (her own), called the *root of trust*.
In this case, Alice was able to find a chain, but in general it might
not be possible to find a path through the web of trust that enables
creation of a certificate chain with a trusted root.
PGP was designed to help humans manage their security, so the discussion
above is phrased in terms of humans. But it applies equally well to machines,
and could be used for authentication of machines. More common for that
task, however, is the use of certificate authorities.