Read a certificate¶
Recover the parameters a message's key was derived from, with the certificate's subkey binding verified rather than assumed.
recipient carries the encryption subkey's fingerprint, its key id, and the
KDFParams that SessionKey needs. Everything except CoordinateBytes, which
is a property of the curve as your key service reports it rather than something
the certificate states:
Both encodings¶
Parse takes binary packets. A certificate published on a web page is
armoured, so dearmour it first — armor.Decode from go-crypto, or whatever
your application already uses. The core does not carry an armour codec for one
caller.
Why it verifies¶
Anyone can append a public subkey packet to a certificate they do not own. Nothing about the format prevents it; what prevents it being believed is the binding signature the primary makes over the subkey.
A parser that skips that check will happily hand back an attacker's key, and a
sender directed at it encrypts to the attacker while believing it is talking to
the certificate's owner. So Parse verifies the binding against the primary
before returning anything, and refuses a subkey that has none.
This matters most when the certificate did not come from you — fetched from WKD, pasted into a ticket, downloaded from a page over a connection you did not pin.
What it does not check¶
- Identity self-certifications. This reads a certificate to find out how to decrypt; the user ID plays no part in the derivation. If you need to know that a name belongs to a key, that is a web-of-trust question and this is not the tool for it.
- Expiry and revocation. Neither is represented here. A certificate this package reads is one you are decrypting against, and a revoked key you still hold still opens old messages.
- Anything but ECDH subkeys. They are the only ones this module can derive against, so others are ignored and a certificate with none is refused.
Errors¶
| Sentinel | Means |
|---|---|
encryption.ErrMalformed |
Not a certificate, truncated, more than one certificate, or no ECDH subkey |
encryption.ErrUnsupported |
A version or algorithm this package does not implement — a v6 key, or a non-RSA primary |
encryption.ErrIntegrity |
A binding signature is present and does not verify |
Walking the packets yourself¶
If you need something Parse does not return, encryption.ParsePacket reads
one packet and hands back the rest, so a sequence is an ordinary loop:
for rest := der; len(rest) > 0; {
pkt, err := encryption.ParsePacket(rest)
if err != nil {
return err
}
// pkt.Tag, pkt.Body …
rest = pkt.Rest
}
Both header forms are handled — the RFC 9580 form a modern implementation writes, and the legacy CTB that older senders still emit. Partial and indeterminate lengths are refused rather than guessed at.