Scenario: You want to temporarily ignore an invalid certificate. (Yes, I know this is usually a bad idea, but sometimes it’s necessary.)
Today: Every application needs its own flag, environment variable, configuration option, and/or UI element to disable validation. If you’re unlucky, there won’t be one. If you’re really unlucky, there won’t be any way to enable validation; even in 2017 there are still lots of poorly written applications like that.
Centralized: There should be a standard environment variable that works with everything, and/or maybe a “security center” applet where you can add a temporary system-wide exemption per-host, or something like that.
Scenario: You want to sniff a secure connection for debugging purposes.
Today: You have to use a MITM proxy, which is gross and needs setup and breaks things, and requires trusting invalid certificates, which doesn’t always work; see above and below.
Centralized: The kernel could just hand decrypted packets to packet sniffing programs, allowing for purely passive observation.
Scenario: You want to ensure that you’re using high-quality ciphersuites.
Today: Up to the application, usually not customizable, so browsers will do the right thing and other applications will have some list the developer copy+pasted that seemed to work. Welp.
Centralized: The system should be able to specify policy for all applications, with the option for the user to override it. After all, it’s almost never actually desirable for a cipher suite to be supported by one application and not another - like, it’s okay if my mail client connects to Google insecurely, but not if my instant messaging client does.
Scenario: You want to add a custom trusted CA, or generally you want different applications to be consistent in their policy decisions.
Today: Different TLS libraries have their own trust store formats and trust rules. If you’re lucky, your TLS library of choice will have some way to use the system trust store, on Windows and macOS where such a thing exists, although who knows if it’ll properly replicate the various rules browsers like to impose, e.g. requiring certificate transparency. If you’re unlucky, you end up with things like Java having its own trust store, or wget on macOS refusing to download any https URLs until you go install some .crt file and point wget to the right path. In both cases, you end up with a separate list of trusted certificates, that requires a separate process if you want to add a custom one, or upgrade to remove newly distrusted roots, etc.
Centralized: Well, there’s already some centralization with system trust stores, but ideally not would those be supported universally, the entire process of “should this TLS connection be established” could be defined and maintained in one place.
Scenario: On a server, you want to run a program that accepts TLS connections.
Today: Each program needs its own copy of the private key and its own TLS configuration, which often doesn’t expose the full range of settings it’s desirable to customize.
Centralized: The system holds the keys (reducing both configuration burden and the danger of leaks); applications can just say “listen on port X using TLS”, and send/receive plaintext on the resulting sockets, and encryption will be handled automatically.
...
I admit there are also some downsides of a centralized design. One of them is updates: these days, on most systems, users update their browsers a lot more than they update the OS, so the browser is likely to be up to date while the OS is not. But "at least the browser is secure, even if other apps are not" is not exactly an ideal outcome, and this too seems like an artifact of history... there's no reason that OS components can't auto-update like browsers do.
Can you explain this? How is something "in the kernel" but implemented as a userspace daemon? Are you suggesting something like a vDSO like how gettimeofday works? That's the only thing I can think of that would come close to that.
My dream would be for "TLS sockets" to be integrated into the system socket API as a first-class citizen next to (plain) TCP and UDP sockets, ideally as part of a POSIX standard. If that were done under the current BSD socket API, it would require at least some kernel support, because that API revolves around file descriptors and system calls like setsockopt, read/write, poll, etc. On the other hand, if it were done as part of a broader revamp of the API, like the one proposed above, well, ideally that revamp would support custom user-level protocols, so TLS could be implemented as one of those rather than involving the kernel.
That sounds like an ideal (if strictly unattainable) outcome. Your design seems like a sort of software-defined violation of the end-to-end principle. If it existed, most apps that have strong feelings about security simply wouldn't use it.
It only takes one confused app autoupdater (typically secured at least in part with TLS) to get pwned.
If browsers want to be resilient to the possibility that the system stack is not secure, I don't mind terribly. After all, browser vendors have dedicated TLS security teams and certificate trust programs, so they can do their own thing and ensure it's secure. Custom TLS stacks get in the way of some of the goals I mentioned, such as user-customized trust settings and packet sniffing, but that's not the end of the world. What I do mind is if the system stack is actually not secure. If nothing else, that means that applications bundled with the system are likely to be at risk.
Non-browser third party applications have to outsource their security policy to someone. They can choose to trust the OS, or to get a TLS stack from somewhere and ship that. In today's world, both approaches have ups and downs from a security perspective. The basic problem is that for maximum security, TLS stacks and their configurations should be updated regularly, mainly to update the trusted certificate list, but also to address vulnerabilities in protocols, ciphersuites, implementation, etc. But many users rarely update their OS. On the other hand, even if you ensure that users update your app (via an autoupdater), you're still responsible for ensuring you ship updates promptly. Even if you cease development because you lost interest or your startup got bought for a trillion dollars or went bankrupt or whatever. And this applies to every single program that wants to establish a secure connection, which these days is basically everything that connects to the Internet.
Of course, on Linux distros, application updates tend to come with system updates, so you probably can't do any better than trusting the system, at least when it comes to updates...
Today, I think many applications which would be happy to trust the system ship their own TLS stacks anyway, just because it's easier - because of fragmentation and the lack of good wrapper APIs in many environments. For example, the Rust ecosystem has thus far mostly depended on OpenSSL bindings for TLS, but there's a desire to move to the new "rust-native-tls" crate, which wraps SChannel on Windows, SecureTransport on Darwin, and OpenSSL elsewhere. Works for Rust; but if there's a C equivalent, I haven't heard of it...
Browsers lately have been imposing conditions on individual root CAs that are more complex than a binary trust/distrust. For example, they have added artificial TLD limits, certificate transparency requirements, or more complex stuff designed to address specific instances of bad behavior by CAs (take a look at mozilla.dev.security.policy). There's no good way to implement that systemwide if there are N different SSL libraries in use, often statically linked, with their own configurations. So you end up with the restrictions only being applied to the browser. Which is less secure.
That's the situation today. Of course, any given issue can be solved many different ways, and there are less disruptive approaches to improving them than what I'm suggesting. My suggested approach is far from necessary, and indeed is unlikely to happen in reality. But you seem to have a gut distaste for it which doesn't resonate with me.
As for server programs "coughing up" private credentials, it's quite the reverse: the administrator doesn't have to stick the credentials in some configuration file for a server that they may not trust particularly well. They don't have to ensure the permissions are correct in N places, but 1. Privilege separation is generally recognized as a good approach to security. (In fact, it could even be possible for unprivileged Unix users to start TLS-enabled servers on high ports without giving them the certs.)
But again, your solution to 'some app makers don't do TLS right' is 'hand over plaintext to the kernel'. The cure seems far, far worse than the disease. I don't think this is a 'gut distaste', it's just that most similar ideas of a generalized way to move encryption away from from the endpoints have failed and standard practice leans very much the other way for reasons that I think are pretty good. My argument isn't so much about anyone going off to implement or not implement this, it's that if you're going to think about this stuff (a perfectly fine thing), you have to meet the bar of the current accepted practice and then offer some, however hypothetical and thought-experimenty improvement. And I'm just not convinced that this idea does.
Edit: You also mention (and I managed to skip over, sorry) the fact that browsers have complex certificate trust handling policies which other apps don't get to leverage. This is true but your example of an app is 'an app that pretends to be a browser'. I think this is a special, narrow case. Consider the dropbox client - it doesn't need or care about CAs, chains of trust, PKI or your system trusted cert store. That's browser stuff. Install mitmproxy and watch dropbox simply fail to work. So your solution is a sort of 'key escrow' demand for any app that just wants to talk TLS, not emulate the complex trust dance of a browser.
That includes both non-HTTP TLS-wrapped protocols like email and IRC, and applications that access user-supplied HTTP URLs but aren't browsers, like media players, RSS clients, git, Matrix (chat), wget, apt-get, etc.
Proprietary services are trickier because there's a question of "security for whom". As someone who mostly uses computers he owns, I would definitely like to be able to sniff Dropbox and see what it's sending. (Actually, Dropbox is a bad example because most Dropbox users already trust them with a lot of personal data, but there are many stories of, e.g., random mobile apps sending user data to servers with no justification.) That's not a security compromise from my perspective because it's my data. But Dropbox or whoever may not want people to get at their app's internal communications, and may see it as a compromise from their perspective. And if I'm using a system where someone else has root, I might agree with them. Of course, root can always attach with a debugger and try to extract the data anyway, but then there's the cat and mouse game of obfuscation...
Yep, I get that and I understand the problem you're describing is an actual problem. I just don't think 'endpoint hands over its plaintext' is the right solution.
I would definitely like to be able to sniff Dropbox and see what it's sending
Well, I'm sure you can, it's just not as easy as firing up tcpdump. But if you wanted to you could, it probably won't even take you long. 'It's not as convenient as firing up tcpdump' is still not a strong argument for 'just hand over the plaintext', in my mind.
I'll wrap this up with a story you might have also seen play out over twitter the last couple of months. Tavis Ormandy, a security engineer currently working on Project Zero at Google has been dissecting various AV products and finding them riddled with pervasive and gross security holes up to and including intercepting TLS traffic and then screwing it up so badly as to make it highly vulnerable.
The response from one vocal AV expert has been 'well, we wouldn't have to do that [and screw it up] if you gave us a tap/API into the plaintext so we can keep you all safe'. The predictable retort of security engineers has been 'LOL, NO'. I think ultimately, that 'LOL, NO' is what you're up against rather than some rando ranting at you on a message board. Enjoyable as it has been!
The only thing providing it in the kernel would do would do is decrease performance and require kernel updates to fix SSL vulnerabilities.