Why does HTTPS not support non-repudiation?
I thought HTTPS would prove that a given content actually came from the origin, by having its contents always signed before transfer.
Since "content" is sent in both directions, providing non-repudiation would require some cryptographic identity capable of signing on both sides of the communication. But TLS actually only requires some proof that the server is the expected one (to protect against man in the middle attacks). And this proof does not even need to be backed by a cryptographic identity, but can also be backed by some shared secret (i.e. PSK).
And while in most cases of TLS a certificate is used on the server side, there usually is no certificate on the client side. This means that non-repudiation could not work in both directions. Requiring some client side certificate would make the practical use of TLS much harder, since not only would each browser need to come with its own trust store as is done currently but also each user needs to have a personal certificate.
On top of this it is questionable if users would really want to have non-repudiation for everything they send. This is probably contrary to the quest for more privacy and anonymity. There is a reason protocols like PGP or S/MIME offer both encryption (including integrity) and signing (non-repudiation) separately.
In short: non-repudiation makes the protocol and the necessary infrastructure more complex and might not be even wanted in many cases. TLS therefore sticks with protecting the communication only, which is enough for most use cases of TLS. If non-repudiation is actually wanted or required (and often it is not) it can be added separately.
TLS is a two-party communication protocol, and HTTPS is not much more than HTTP over TLS. Its threat model considers only two participants (the client and the server) and its goal is to secure the communication against attackers who might read or modify the data that is exchanged. Non-repudiation does not fit in this threat model at all: it's about allowing a third party to verify properties of the communication, which was never a goal of TLS or HTTPS.
Your claim that “non-repudiation is really important in communications” is false. Non-repudiation is a rare property, and is often not important or even not desired. Deniability (the ability for one or both parties to deny that a particular exchange of data took place) is about as commonly desirable and achievable, and it contradicts non-repudiation. TLS guarantees neither non-repudiation nor deniability, but is compatible with both. For non-repudiation, you'll want to at least have the non-denying party sign the data to commit using an asymmetric signature scheme. For deniability, you'll want to take precautions against recording by a reliable third party. (Neither of these are enough! Both non-repudiation and deniability are complex properties.)
Furthermore, even when non-repudiation is important, it is not important in communications. It's mostly orthogonal to how communication works. Non-repudiation is fundamentally an end-to-end property: one or more entities commit to a certain piece of data. TLS is a point-to-point communication protocol, and HTTPS commonly involves multiple entities generating content on the server side.
Even end-to-end communication protocols rarely guarantee non-repudiation on their own. A signature does not guarantee non-repudiation, since it leaves open the “nuclear option” that the signing party could deliberately leak its signing key. In fact, for this reason, it's impossible to achieve general non-repudiation by purely cryptographic means (i.e. without resorting to a trusted third party). The most you can achieve is to design a protocol where the nuclear option causes so much collateral damage that the signer would not want to use it, and that's a judgement that can only be made in a specific setting.
It would be possible to modify the TLS protocol to add an asymmetric signature to every message, which would commit each party to having sent these messages, short of invoking the nuclear option. But:
- In many cases, the client is not authenticated. So only the server would be committing to anything, not the client.
- Depending on the protocol carried over TLS, the signature may or may not commit to anything meaningful. Often, the data exchanged includes parts that are meaningful to both sides, but not to third parties that could be interested in verifying that the exchange took place. For example, it might involve references to cached data, or references to the current state of data on the server that are not verifiable after the fact (“delete the third row”).
- Depending on the protocol carried over TLS, the signed data might include parts that must not be revealed. Since TLS does not know anything about the data that it carries, the most it can guarantee is the authenticity of the whole exchange, or of some prefix of it. So if, for example, the communication starts with a user logging in with a password, there would be no way to authenticate subsequent data without revealing the user's password.
- The cost of calculating and verifying the signature on every packet would be very high. Asymmetric cryptography is a lot more expensive than a MAC.
- The amount of data to exchange would be slightly larger. (Significantly larger if it comes to post-quantum signature schemes.)
If you need non-repudiation:
- Review your threat model carefully. Identify which party might want to lie about the data that it sent, and which party it must be accountable to.
- Protect the data that needs to be protected. This will almost never going to be the whole communication — for example logins typically need to be excluded. Generally, there'll be one or more round-trips to determine the data, and then the server will send a signed message.
- The signing key used for the non-repudiable data may be different from the signing key used for communication (the former belonging to the backend, the latter belongining to the frontend).
Among other reasons, I'm not prepared to say at a protocol level that there isn't a way to say to a CGI server, "echo this content". If you don't have non-repudiation, then this is a non-issue for security reasons; but if you have it at a protocol level, than this is a security breach.
If I want non-repudiation I'll use a signed-content file format, not a signed delivery protocol. X509 can sign quite a few things including zip files.