Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow linking to a different openssl library #38015

Open
Meai1 opened this issue Jun 17, 2020 · 5 comments
Open

Allow linking to a different openssl library #38015

Meai1 opened this issue Jun 17, 2020 · 5 comments

Comments

@Meai1
Copy link

Meai1 commented Jun 17, 2020

Issues like this are alive for more than 5 years: #14741
Intended effect of linking to a system openssl was supposedly that we get updated openssl sooner. This is clearly not happening because we lack the c# api that would go along with the openssl anyway.
The goal should be to give power to users.

  1. let me switch out the openssl version that dotnet links to
  2. dotnet has to give me c# apis that correspond to new features in the newer openssl version

Needed for that:

  1. Report which openssl symbols are being discovered by dotnet and if there are any problems or compatability changes then report that loudly.

  2. Expose the underlying OpenSSL apis under the same naming.
    As I've indicated in this issue: API call order matters but it shouldnt aspnetcore#11833
    Names like "CipherAlgorithmType.Rc4" dont really mean anything by itself in OpenSSL, correct me if I'm wrong here but in OpenSSL terms to specify "Rc4" does not let me know which exact cypher would be picked because the real cyphers are long strings like: "TLS_RSA_WITH_RC4_128_MD5"
    So now I'm supposed to somehow figure out what Rc4 actually means in terms of the real underlying implementation. This is just extra work for me as an enduser, if I were using C then I could directly link to openssl and everything would be clear because I call SSL_CTX_set_cipher_list() and there wouldnt be any doubt about what it does. It's not clear to me why c# doesnt just do that also. I dont see any harm in making c# use openssl terms even if it eventually switches the underlying ssl library away from openssl. It's just an api interface.

And to strengthen my argument, Golang does exactly that:
https://stackoverflow.com/questions/31226131/how-to-set-tls-cipher-for-go-server
It simply lets you specify the cipher suites directly by their actual names. I don't see any possible argument why this should be more complicated than that.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Security untriaged New issue has not been triaged by the area owner labels Jun 17, 2020
@ghost
Copy link

ghost commented Jun 17, 2020

Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq
Notify danmosemsft if you want to be subscribed.

@vcsjones
Copy link
Member

vcsjones commented Jun 17, 2020

let me switch out the openssl version that dotnet links to

For the most part .NET does not link directly against OpenSSL. Each version of .NET Core has a preferred way of loading an OpenSSL version, like 2.1 prefers loading openssl 1.0 and 3.1 prefers loading openssl 1.1. @bartonjs has a better answer on this. However if you can use the environment variable CLR_OPENSSL_VERSION_OVERRIDE to load a particular version.

That environment variable should be set to "1.1.1" or "1.0.2" as an example, and when .NET Core looks for libssl it will look for that version. The library needs to be in a location that the OS loader will look.

I call SSL_CTX_set_cipher_list() and there wouldnt be any doubt about what it does. It's not clear to me why c# doesnt just do that also

.NET Core 3 allows using CipherSuitesPolicy.AllowedCipherSuites that I think is doing what you are asking for. This is set at the connection level, not the process level. This works as long as you have OpenSSL 1.1.1 available (or are on macOS).

For SslStream, this looks something like this.

using System.Net.Security;
using System.Threading.Tasks;

static class Scratch {
    public static async Task Main() {
        SslStream stream = new SslStream(System.IO.Stream.Null); //Some real stream
        var options = new SslServerAuthenticationOptions();
        var aeadOnly = new TlsCipherSuite[] {
            TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256,
            TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
            TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
        };
        options.CipherSuitesPolicy = new CipherSuitesPolicy(aeadOnly);
        await stream.AuthenticateAsServerAsync(options);
    }
}

I'm not sure how or if Kestrel exposes this so that an ASP.NET application can define cipher suites.

@bartonjs
Copy link
Member

.NET builds against OpenSSL in two different ways: portable (used by the .tar.gz bundle on our site and the package-manager packages we provide) and direct (more likely used by in-distro packages).

In direct mode, there's no way to intercept things. It was decided when the distro built, as part of the distro dependency management scheme.

In portable mode, you can influence which version of OpenSSL gets loaded by setting the CLR_OPENSSL_VERSION_OVERRIDE environment variable to the SONAME version portion of the library you want to load (e.g. for libcrypto.so.1.1 you'd set it to 1.1). If the library that gets loaded has incompatible API with what we expect, the process terminates.

For either mode you can identify what got loaded via System.Security.Cryptography.SafeEvpPKeyHandle.OpenSslVersion

Intended effect of linking to a system openssl was supposedly that we get updated openssl sooner.

For security updates, as managed by the OS. New functionality isn't a goal.

Issues like [supporting EdDSA] are alive for more than 5 years

New algorithms are hard to add, because we try to avoid adding shiny new things that aren't supported on all the OSes. Last I checked, Windows CNG and Apple Security.framework don't support EdDSA (at least, not through public API), which means using that algorithm would result in a PlatformNotSupportedException.

It's not clear to me why c# doesnt just do that also. I dont see any harm in making c# use openssl terms even if it eventually switches the underlying ssl library away from openssl. It's just an api interface.

Being a thin wrapper is great while the abstractions don't change. When they do (such as changing from Windows to Linux or vice versa, or a major version of a library with significant changes), it's then a nightmare of a compat burden. So we're very selective about what we let leak through these days.

It simply lets you specify the cipher suites directly by their actual names.

So does .NET: https://docs.microsoft.com/en-us/dotnet/api/system.net.security.sslserverauthenticationoptions.ciphersuitespolicy?view=netcore-3.1#System_Net_Security_SslServerAuthenticationOptions_CipherSuitesPolicy

@bartonjs bartonjs added this to the Future milestone Jun 23, 2020
@bartonjs bartonjs removed the untriaged New issue has not been triaged by the area owner label Jul 7, 2020
@MatthewLymer
Copy link

This probably won't happen, but a ManagedSslStream implementation would be nice for my use-case (transparent ssl-bump proxy).

Having Linux supporting TLS 1.3, while Mac and Windows supporting TLS 1.2 (albeit with different ciphers), makes it very difficult to figure out what's going to happen in runtime.

There's already sites out there that don't support TLS 1.2 or older (whether that's smart is a different topic), it sucks that our application functioning properly is dependent upon the underlying OS having SChannel, LibreSsl, or OpenSsl 1.0, or OpenSsl 1.1.

@bartonjs
Copy link
Member

This probably won't happen, but a ManagedSslStream implementation

Yeah, that's currently an anti-goal. While I agree it would help smooth out some experience, doing TLS properly is a lot harder than it sounds (HeartBleed and ROBOT are two implementation vulnerabilities, vs BEAST with was a protocol-level attack, or CRIME/BREACH which are application-level attacks), and it would give up on implementation-specific benefits (central policy management, Windows' implementation keeps the private keys out-of-proc, etc).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants