Check the S/MIME half against a real server, instead of assuming it
The section offered "an OpenPGP public key or an S/MIME certificate" and
only the first half had ever been tried. Every probe behind it used
OpenPGP keys, and every message the registry returns names OpenPGP --
including for input that is not OpenPGP at all -- so the server reads as
though OpenPGP were the only format it knows. Shipping the claim on that
evidence would have been a guess dressed as a feature, which is the one
thing this section is written not to do.
It holds. Confirmed live on 0.16.20 (2026-09-05) with a self-signed
X.509 certificate carrying emailProtection and an email: SAN:
registered, read back, destroyed. And Stalwart parses it as seriously as
it parses OpenPGP -- a malformed certificate is refused by a decoder of
its own, "Failed to decode X509 certificate: BER decoding error:
Expected Tag { class: Universal, value: 16 } tag…", which is a third
rejection wording and the reason the S/MIME half is real rather than
decorative. The mock now returns it for a certificate, so the branch
exists somewhere a client can meet it.
One thing found on the way: expiresAt is the registry's field and is not
derived from the key. A certificate valid for a year registers with
expiresAt null, so the card says "No expiry set" about a credential that
does expire. Left as it is, deliberately: reading the real date means
parsing the certificate, which is the second opinion this section
refuses to offer, and a date extracted here would disagree with the
server's own field the moment the two ever differed. What the row
reports is what the registry holds, and KNOWN-ISSUES says so.
This commit is contained in:
+11
@@ -1236,6 +1236,12 @@ first two:
|
||||
checked would be a second opinion, and the one that counts would still be the
|
||||
server's — its message is shown verbatim, the way password-policy rejections
|
||||
already are.
|
||||
- **Certificates are parsed too, by their own decoder.** The registry is not
|
||||
OpenPGP-only, though every other message it returns reads as though it were: a
|
||||
self-signed X.509 certificate registers, reads back and removes cleanly, and a
|
||||
malformed one is refused with *"Failed to decode X509 certificate: BER
|
||||
decoding error…"*. So the S/MIME half of this section is real, and the server
|
||||
is the thing checking it in both formats.
|
||||
- **A key that parses can still be refused, and says something else.** A
|
||||
sign-and-certify key with no encryption subkey — which is what
|
||||
`gpg --quick-generate-key` produces by default — comes back *"Could not find
|
||||
@@ -1252,6 +1258,11 @@ first two:
|
||||
reloads the list instead of believing what came back. Renaming and removing
|
||||
both work; removal leaves the registry genuinely empty.
|
||||
|
||||
**`expiresAt` is the registry's field, not the key's.** A certificate valid for
|
||||
a year registers with no expiry set, and the card says so. Reading the real one
|
||||
means parsing the certificate, which is the second opinion this section exists
|
||||
not to offer.
|
||||
|
||||
The kind badge — OpenPGP or S/MIME — is read from the armour header alone, which
|
||||
is a label rather than a parse, and the excerpt beside each key is deliberately
|
||||
not called a fingerprint: computing a real one means parsing the key, and naming
|
||||
|
||||
Reference in New Issue
Block a user