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

SecurityContext with minimal protocol version #37173

Closed
sedem7 opened this issue Jun 6, 2019 · 26 comments
Closed

SecurityContext with minimal protocol version #37173

sedem7 opened this issue Jun 6, 2019 · 26 comments
Assignees
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. customer-google3 library-io P1 A high priority bug; for example, a single project is unusable or has many test failures type-enhancement A request for a change that isn't a bug type-security

Comments

@sedem7
Copy link

sedem7 commented Jun 6, 2019

We should be able to choose security protocol as strong as possible.
At present, there is line in runtime file: https://github.com/dart-lang/sdk/blob/master/runtime/bin/security_context.cc which sets protocol to version TLS1.0.

(:825) SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); // cannot be changed from dart

Please, add option to choose minimal protocol version from Dart SecurityContext.

@rmacnak-google rmacnak-google added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io type-enhancement A request for a change that isn't a bug labels Jun 6, 2019
@rmacnak-google
Copy link
Contributor

@sortie

@sortie
Copy link
Contributor

sortie commented Jun 7, 2019

Hmm. That's not good enough.

Wikipedia says "In October 2018, Apple, Google, Microsoft, and Mozilla jointly announced they would deprecate TLS 1.0 and 1.1 in March 2020.[11]" so we should think about that as well.

I'll need some time to understand this code a bit better and what incompatibilities/breaking changes might occur if we change this or expose it in Dart. Could be interesting to a do an SSL labs test with a dart client / server and see exactly what they allow.

@sortie sortie added P2 A bug or feature request we're likely to work on type-security labels Jun 7, 2019
@sedem7
Copy link
Author

sedem7 commented Jun 7, 2019

Just as info.
We have following piece of code (sample), which worked well, until June this year, when specification for web service had changed, and now is only allowed to use TLS1.2 protocol. This had led us to error SSLV3_ALERT_HANDSHAKE_FAILURE(tls_record.cc:586).

SecurityContext context = new SecurityContext(withTrustedRoots: true)
  ..setTrustedCertificates('tls_connection_cert')
  ..usePrivateKey('private_cert.p12', password: 'password');

  await SecureSocket.connect("service_host", 9002, context: context).then((socket) {
    print('Connected to: '${socket.remoteAddress.address}:${socket.remotePort}');
    socket.destroy();
  });

Since project is Flutter based, we quickly turn to Platform channel options, and at the moment we are calling native solutions. Java example:

KeyManager[] privateCert; // private_cert.p12
TrustManager[] publicCert; // tls_connection_cert
SSLContext ssl = SSLContext.getInstance("TLSv1.2");
ssl.init(privateCert.getKeyManagers(), publicCert.getTrustManagers(), null);
SSLSocket socket = (SSLSocket)ssl.getSocketFactory().createSocket("service_host", 9002);
socket.startHandshake();
socket.close();

We have probe with Wireshark tool. Using vanilla dart:io in a standalone app, Dart sends a 1.2 Client Hello inside a 1.0 header, offering 15 cipher suites. On Java side there is 1.2 header with 45 chiper suites.
Our particular server chooses TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f) chiper, which is not present in those 15 choices, that Dart send in its Client Hello.

@sedem7
Copy link
Author

sedem7 commented Jun 7, 2019

None, I was afraid I raised “bad” question. This was before I deep dive into Dart source code to find reason of the problem.

@sedem7 sedem7 reopened this Jun 7, 2019
@TobiasHeidingsfeld
Copy link

How / When can I enable TLS 1.2 in Dart? Browsers are complaining about the standart settings.

@natebosch
Copy link
Member

@ferhatb @yjbanov @jonahwilliams - is this going to impact our developer workflow for flutter web?

@jonahwilliams
Copy link
Contributor

I'm not quite sure what the implications would be for the tool, fyi @zanderso

@zanderso
Copy link
Member

/cc @aarongreen for advice about what the right thing to do here is:

https://github.com/dart-lang/sdk/blob/master/runtime/bin/security_context.cc#L808

@bonesyblue
Copy link

Hi all,

I too was having issues handshaking from my Flutter app with an IOT message broker that supported a minimum TLS v1.2 connection. Whilst searching for an explanation, I found #37157, #37173 and #41061 which are similar issues discussing problems connecting via TLS with Dart. From what I understand, it appears that the connection message headers are TLS v1.0 conform, meaning my server rejected the request as insecure.

In addition, #35462 discusses issues with using the setTrustedCertificates() method from the dart:io library. This lead me to the following TLS/SSL with Dart article that ultimately helped me solve my issue. I have included code snippets of both the solution and what I had previously been doing wrong below. I hope this helps anyone else struggling with this issue and saves you the time and head-scratching that I went through ⏰

Solution 🚀

pubspec.yaml

...
assets: 
    # Add the required certificates to your bundle. Note: Your personal use-case may be different,
    # so just make sure to have a reference somewhere to the certificates required to negotiate a 
    # secure connection.
    # 
    # The certificate_chain.pem file contains the required client certificate together with the root 
    # authority certificate. Note: order is important. The client certificate must come before the 
    # root authority in this file! Mine looks something like this:
    #
    # -----BEGIN CERTIFICATE-----
    # Paste your client certificate here
    # -----END CERTIFICATE-----
    # -----BEGIN CERTIFICATE-----
    # Paste your root authority certificate here
    # -----END CERTIFICATE-----
    #
    - assets/path_to_certificates/certificate_chain.pem
    - assets/path_to_certificates/private.pem

client.dart

...
// Obtain the raw byte data of the certificate chain and private key file contents
ByteData certificateChain = await rootBundle.load("assets/path_to_certificates/certificate_chain.pem");
ByteData privateKey = await rootBundle.load("assets/path_to_certificates/private.pem");

final context = SecurityContext.defaultContext;
context.useCertificateChainBytes(certificateChain.buffer.asUint8List());
context.usePrivateKeyBytes(privateKey.buffer.asUint8List());

await SecureSocket.connect(host, port, context: context)
// Party time 🎉 
...

Erroneous code (for reference only of what didn't work as expected) ❌

The following code results in a HandshakeException SSLV3_ALERT_BAD_CERTIFICATE(tls_record.cc:587)

pubspec.yaml

...
assets: 
    # The root CA and client certificates were previously separate. The solution was to combine
    # them into a single certificate chain (see above)
    - assets/path_to_certificates/root_ca_cert.pem
    - assets/path_to_certificates/client_cert.pem
    - assets/path_to_certificates/private.pem

client.dart

...
// Obtain the raw byte data of the client & root CA certificates and private key file contents
ByteData rootCACertificate = await rootBundle.load("assets/path_to_certificates/root_ca_cert.pem");
ByteData clientCertificate = await rootBundle.load("assets/path_to_certificates/client_cert.pem");
ByteData privateKey = await rootBundle.load("assets/path_to_certificates/private.pem");

final context = SecurityContext.defaultContext;
context.setClientAuthoritiesBytes(clientCertificate.buffer.asUint8List());
context.setTrustedCertificatesBytes(rootCACertificate.buffer.asUint8List())
context.usePrivateKeyBytes(privateKey.buffer.asUint8List());

await SecureSocket.connect(host, port, context: context)
// HandshakeException 💥  
...

@alidhkh
Copy link

alidhkh commented Sep 21, 2020

Hi all,

I too was having issues handshaking from my Flutter app with an IOT message broker that supported a minimum TLS v1.2 connection. Whilst searching for an explanation, I found #37157, #37173 and #41061 which are similar issues discussing problems connecting via TLS with Dart. From what I understand, it appears that the connection message headers are TLS v1.0 conform, meaning my server rejected the request as insecure.

In addition, #35462 discusses issues with using the setTrustedCertificates() method from the dart:io library. This lead me to the following TLS/SSL with Dart article that ultimately helped me solve my issue. I have included code snippets of both the solution and what I had previously been doing wrong below. I hope this helps anyone else struggling with this issue and saves you the time and head-scratching that I went through ⏰

Solution 🚀

pubspec.yaml

...
assets: 
    # Add the required certificates to your bundle. Note: Your personal use-case may be different,
    # so just make sure to have a reference somewhere to the certificates required to negotiate a 
    # secure connection.
    # 
    # The certificate_chain.pem file contains the required client certificate together with the root 
    # authority certificate. Note: order is important. The client certificate must come before the 
    # root authority in this file! Mine looks something like this:
    #
    # -----BEGIN CERTIFICATE-----
    # Paste your client certificate here
    # -----END CERTIFICATE-----
    # -----BEGIN CERTIFICATE-----
    # Paste your root authority certificate here
    # -----END CERTIFICATE-----
    #
    - assets/path_to_certificates/certificate_chain.pem
    - assets/path_to_certificates/private.pem

client.dart

...
// Obtain the raw byte data of the certificate chain and private key file contents
ByteData certificateChain = await rootBundle.load("assets/path_to_certificates/certificate_chain.pem");
ByteData privateKey = await rootBundle.load("assets/path_to_certificates/private.pem");

final context = SecurityContext.defaultContext;
context.useCertificateChainBytes(certificateChain.buffer.asUint8List());
context.usePrivateKeyBytes(privateKey.buffer.asUint8List());

await SecureSocket.connect(host, port, context: context)
// Party time 🎉 
...

Erroneous code (for reference only of what didn't work as expected) ❌

The following code results in a HandshakeException SSLV3_ALERT_BAD_CERTIFICATE(tls_record.cc:587)

pubspec.yaml

...
assets: 
    # The root CA and client certificates were previously separate. The solution was to combine
    # them into a single certificate chain (see above)
    - assets/path_to_certificates/root_ca_cert.pem
    - assets/path_to_certificates/client_cert.pem
    - assets/path_to_certificates/private.pem

client.dart

...
// Obtain the raw byte data of the client & root CA certificates and private key file contents
ByteData rootCACertificate = await rootBundle.load("assets/path_to_certificates/root_ca_cert.pem");
ByteData clientCertificate = await rootBundle.load("assets/path_to_certificates/client_cert.pem");
ByteData privateKey = await rootBundle.load("assets/path_to_certificates/private.pem");

final context = SecurityContext.defaultContext;
context.setClientAuthoritiesBytes(clientCertificate.buffer.asUint8List());
context.setTrustedCertificatesBytes(rootCACertificate.buffer.asUint8List())
context.usePrivateKeyBytes(privateKey.buffer.asUint8List());

await SecureSocket.connect(host, port, context: context)
// HandshakeException 💥  
...

You are a hero.

@intoxicated
Copy link

intoxicated commented Feb 17, 2021

This ticket has been opened for almost 2 years yet I can't find official docs or any clear guidance/answers from dart team how to deal with TLS 1.2 / 1.3 problem if there are any :( any updates on this?

@travishaagen
Copy link

I can confirm that TLS 1.2 works with recent versions of Flutter and its HttpClient. I wanted to lock down which algorithms it would negotiate, so I did some experimenting. For my HTTP server, I landed on the following cipher suite priority ordering during SSL/TLS negotiation:

// tls 1.3
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
tls.TLS_AES_128_GCM_SHA256,

// tls 1.2
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
// following is supported by Flutter clients (Jan. 2021)
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,

With this ordering, Flutter will currently connect using TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and that's an acceptable choice.

My server only supports TLS 1.2 and 1.3.

If, for some reason, you don't have control over all this for your HTTP server, then expect Flutter to negotiate a lower quality cipher.

@gustav3d
Copy link

gustav3d commented Feb 20, 2021 via email

@proneotiv
Copy link

Any progress from this issue?

We are currently developing a medical device (app) with flutter that has to meet certain securtiy standarts (by law).
One of those standarts is that we explicitly have to specify the tls version the app uses and/or block connections that
use a different encryption protocol.
For example: If the tls protocol version is set to 1.2, connections using tls version 1.3 should be blocked. Only the specified version should be allowed.

Additionally, our certificates are created from a common CA , so all HTTPS connections are accepted by default and we cannot "unlock" connections by specifiying a certificate inside the app.

Basically we need to make sure that our app only connects to our backend (specific domain) and that only one specific type of encrpytion is accepted.
With the given means in flutter I simply cannot guarantee that those specifications are met.

It woult be nice if flutter would support some more strict security features in the future.

Also we are currently using dio as http client for the app. Is there a way to meet the specifications mentioned above with it?

@cconstab
Copy link

cconstab commented May 20, 2021

I thought this would be such a simple fix.. We noticed that we could force a secureServerSocket to some unwanted tls1.0 see below.. But good news I think was that I can force a connection to TLS1.3 using openssl. But still there seems no way to only accept version TLS1.x through the dart sdk.. Seeing as behind the scenes openssl is being used it should be exposable, as openssl the command line can do it..

TLS1.3 on Dart version .... Dart SDK version: 2.13.0 (stable) (Wed May 12 12:45:49 2021 +0200) on "windows_x64"

runtime code is here line 805

$ openssl s_client -tls1_3 10.64.64.64:9999
CONNECTED(00000154)
---
subject=CN = vip.ve.atsign.zone

issuer=C = AT, O = ZeroSSL, CN = ZeroSSL RSA Domain Secure Site CA

---
No client certificate CA names sent
Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512:RSA+SHA1
Shared Requested Signature Algorithms: ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384:RSA-PSS+SHA512:RSA+SHA512
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 3917 bytes and written 309 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
Hello

Plus the example connection that is allowed but we would rather it was not

New, TLSv1.0, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1
    Cipher    : ECDHE-RSA-AES256-SHA
    Session-ID: EAE482E92E908BC032A5EB3056E8CFD4E27782798C23B9E6CA5377E70BAC4EBB
    Session-ID-ctx:

@mraleph
Copy link
Member

mraleph commented May 20, 2021

/cc @a-siva @aam maybe we should consider expanding the SecurityContext constructor to allow specifying minimum/maximum TLS version as well as cyphers?

@mraleph mraleph added P1 A high priority bug; for example, a single project is unusable or has many test failures and removed P2 A bug or feature request we're likely to work on labels Jul 2, 2021
@mraleph
Copy link
Member

mraleph commented Jul 2, 2021

Bumping the priority to P1. I suggest the following:

  • We bump default minimum TLS version to 1.2
  • We expand the SecurityContext constructor to allow specifying minimum/maximum TLS version as well as cypher lists for TLS versions below 1.2

@alexrainman

This comment has been minimized.

@alexrainman

This comment has been minimized.

@mraleph

This comment has been minimized.

@alexrainman

This comment has been minimized.

@alexrainman

This comment has been minimized.

@vsmenon
Copy link
Member

vsmenon commented Aug 4, 2021

Any updates here? @a-siva @mraleph - should we assign this? I'm tentatively adding to the next milestone as it's P1 with an internal customer.

@a-siva a-siva self-assigned this Aug 4, 2021
@a-siva
Copy link
Contributor

a-siva commented Aug 4, 2021

@aam
Copy link
Contributor

aam commented Aug 4, 2021

  • We bump default minimum TLS version to 1.2
  • We expand the SecurityContext constructor to allow specifying minimum/maximum TLS version as well as cypher lists for TLS versions below 1.2

I think this two tasks can be done independently and only first one requires breaking change(#41135)

@a-siva
Copy link
Contributor

a-siva commented Oct 4, 2021

https://dart-review.googlesource.com/c/sdk/+/140481 has landed, closing this issue.

@a-siva a-siva closed this as completed Oct 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. customer-google3 library-io P1 A high priority bug; for example, a single project is unusable or has many test failures type-enhancement A request for a change that isn't a bug type-security
Projects
None yet
Development

No branches or pull requests