Questions about verification
I'm slightly confused by the verification flow on the receiving side for misfin(B). Apologies if some of these questions are already obvious in the spec/best practices/reference examples and I've just missed/misunderstood!
I'm specifically trying to implement the case where the server's certificate is a self-signed CA and there may be multiple mailboxes (each with certs signed by that CA).
My understanding
My understanding of the process, starting from the end of the TLS handshake is below. At this starting point, the server has a client certificate (that it knows has been sent by a client that has access to the private key) and the client has started to send the message text to the server.
The server now does the following:
- Basic verification of the client cert (e.g. expiry date)
- Get identity information (mailbox, hostname, blurb, fingerprint) from the client cert (see Question 1)
- If the client cert is issued by (or is the same as) the stored server cert for the hostname, and the fingerprint matches what I've stored for that mailbox, then no further verification is needed and the message can be processed (See Question 2)
- If I haven't seen this server before, I need to verify that the client certificate is real
- My server sends an empty misfin message to the mailbox@hostname address from the client certificate and caches the server certificate presented by that host (see Questions 3 and 4)
- The sending server does whatever validation it wants on my empty message (hopefully little/none to avoid the infinite verification loop issue) and sends back a success message with the fingerprint for the mailbox
- My server checks that the client certificate was issued by the server I just connected to and that the fingerprint matches what the sending server just told me and I either accept or reject the message
- If I accept the message, my server caches the hostname certificate and the mailbox thumbprint for future verification
Questions
- 1) Should the server read in the message data before looking at the client cert? If it's an empty message (i.e. just misfin://mailbox@hostname{space?}{CRLF}), then does the server actually need to validate anything (or even check that a client certificate is present at all)? Should I just return a success code and the fingerprint of the requested mailbox in this case? It feels weird to read the message before checking the credentials, but it would mitigate the issue jeang3nie mentions in the comments here:
- 2) If the identity information all matches something I've already seen and verified, should I just accept it without further verification, or carry on and check it's still the current fingerprint for that address (by sending an empty message as if I've never seen the client before)? What if it's a new mailbox from a trusted host? If someone has their (mailbox or server) certificate stolen I guess they can send one last message to everyone they've previously contacted to tell them to manually revoke trust for the compromised certificate, to mitigate this?
- 3) I assume my server presents its own (CA) certificate here as the client cert on the connection? Should the mailbox in the USERID field on this certificate be treated as the default/admin mailbox for the server, or could/should it be a 'noreply' address that rejects all (non-empty) messages?
- 4) If the sending server replies to my empty message with a redirect response, does that mean I've picked the wrong Subject Alternative Name from the sending certificate? Is it valid to have multiple SANs in a misfin certificate? Should I follow the redirect or treat that as a failure to verify?
2023-07-17 · 2 years ago · 👍 sirwilburthefirst
3 Comments ↓
Per you first question, that's basically the scheme I plan to go with, lacking official direction from the spec. Read the message, reply with the usual success status code and fingerprint, but cache the message rather than storing it in the inbox. Then close the connection and do the verification. I would take it a step further and if the verification fails place the offending message into the server admin's mailbox along with a header telling them what the issue was with validation, so that there is a record of someone attempting to spoof an address, along with blacklisting that certificate and possibly IP.
As to your second question, I assume that you mean the client has sent a certificate that matches the mailbox they claim to be sending from and which has previously been trusted, and the only difference is the originating IP address? If that's the case, I would accept the message. I'd like to be able to send mail from my laptop when I'm not at home without having to phone home to the local network to have the server send the message. Indeed, the spec doesn't even cover how remote sending might work anyway. This is actually one of the use cases that drew me to Misfin.
As for your third and fourth questions, any response from me would be a best guess without having actually having given it much thought beforehand.
Thanks for the answers! Caching the message and performing the validation later is an interesting idea I hadn't thought of. I don't think I'll go that far but it could be a good way to prevent bad actors from overloading servers with loads of empty requests.
For the second question I think I was overthinking things and confusing myself. I didn't mean verifying the incoming IP (I agree, the fact that clients can just send messages directly to recipient servers is a plus [1]) I actually meant to ask whether trusted hosts should be re-verified some/all of the time. I now think that's probably a waste of time (and resources) in most cases (although see below for caveats).
The second part of the question was whether I need to verify a new mailbox from a previously seen host (i.e. check that the fingerprint matches). I think this is worth doing, specifically for the case of stolen certificates.
This is probably rare, but I hope it gets addressed in the 'best practices' document at some point. I think the process for stolen user certificates should be (in order):
- Issue a new certficate and configure your server to start sending that as the fingerprint for your mailbox
- Send a message to anyone you have ever previously contacted via misfin, telling them to stop trusting the old certificate's fingerprint. This message should be sent using the old (compromised) certificate
- Send all future messages with the new certificate (although these may get rejected until the recipient has had the chance to read and take action on your earlier message)
If a server certificate is stolen, the server admin should inform all their users to do the above after they generate a new CA (probably by inserting a message directly into user inboxes).
Perhaps periodically re-verifying trusted server CAs and mailbox fingerprints would be a good general strategy to mitigate these concerns?
[1] unless I'm wrong, one downside of this is that you have to be careful when sending a message to someone for the first time (from a given device) while on an untrusted network. Unlike on Gemini, where evil DNS servers 'just' mean you could see incorrect information, with misfin the bad guy has received your message (which could theoretically contain private or sensitive information). They can't reply from that spoofed address (because your server's DNS query can't be tricked in the same way), but it feels like a more serious issue with TOFU and self-signed certs than the corresponding Gemini case.
Obviously, whatever the messaging protocol, they could send you to a fake contact page with a replaced contact address, but this attack is still possible if the victim knows the address by heart or copies it from a known trusted capsule (e.g. their mail server).
Sorry reply now, just for the easy part. Agreed that periodic re-validation is probably a good idea.