-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Single-binary ECC (ECDSA/ECDHE) TLS support for SubstrateVM #1336
Comments
TLS doesn't really work though (oracle/graal#951 and oracle/graal#1336). Also Tomcat Native fails to load with an initial JNI error. Update some version numbers.
Not relevant to the discussion, but I’m impressed with your level of detail and testing process 👍🏼 Amazing level of detail for anyone coming here for help. Really great contribution to people (like me!) testing out graal, thanks! |
Have you got this test working without graal? That seems to me to be the first step. n.b. inserting the BC providers at the top of the list.
You shouldn't need to disable the SunEC provider, but if you do, you should presumably also disable SunJSSE at the same time when using bctls. At this point I've got it working outside of Graal, so I'll switch to Graal next. With BC:
Without
|
Now hitting first this with Graal - #378
Then after fixing above
Annoyingly, the Security feature seems really tied to SunEC - https://github.com/oracle/graal/blob/9ce4ed93a2797e922ff3a364e1f7b192984b9537/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java But it feels close... |
Right: you've hit why I disabled SunEC for Graal :) |
@lvh OK, makes sense. That wasn't clear that you were also hitting it when just trying to use SecureRandom with bctls. |
@lvh on further testing outside of Graal, I can't get bctls working with JDK8. Works fine with JDK11, just switching the execution JVM for running the test, nothing else. But I suspect the issues I'm seeing with Graal are now related to that instead. So I'm not going to spend more time getting bctls working with Graal. |
Do you have a reproducer project? Most of the reason BCTLS exists is good crypto on old JDKs (and I’ve certainly used BCTLS on JDK8, at least I think?) so that’s a very surprising statement to me :) |
@lvh I've linked above. OkHttp tries to drive the selection of which cipher suites to use. It's possible that this is what's causing the issue, negotiating JceChaCha20Poly1305 on JDK 8. |
19.3.0 fixes this issue by introducing libsunec from the JDK whenever appropriate. Hooray! |
#951 addresses the issue that SunEC becomes mandatory for GraalVM native-image binaries doing TLS. While this is fine for some uses of native-image, people sometimes want good TLS support, including ECC, in a single binary. My example in point for this is shipping CLI tools.
In #951, a workaround was discovered that easily disables the SunEC provider. A downside is that only DHE/RSA is supported. The purpose of this ticket is to examine how to get single binary that still supports ECDHE.
One way that this could be resolved is if native-image supported e.g. Sulong's LLVM implementation for System.loadLibrary, or native-image learned how to System.loadLibrary libraries that are actually embedded in the image. I have no idea if that's possible or realistic: but I'm not an Oracle employee so deep engineering on GraalVM itself feels a little scary :) I'm calling this approach "loading embedded dynamic libraries".
Another way to hack this together is to add libsunec.so (or .dylib or .dll) as an embedded resource, set
java.library.path
to a few well-known locations that are likely to be writable across platforms (presumably more than one such location), and write the dylib out at runtime (and delete it when you're done). I'm assuming the runtime impact of that is not too terrible, but the implementation. I'm calling this approach "loading libraries shipped as resources". Because the code that calls System.loadLibrary is generated by SubstrateVM, it's not clear to me if I can make that use System.load with an explicit path, or if you have to modifyjava.library.path
.Another way that perhaps doesn't require as much hacking on Graal internals is to use a different provider. The best (on the metric of "satisfying my proclivities as a cryptographic engineer") provider available is probably conscrypt, a provider published by Google using BoringSSL. I believe it's the default in modern Android. Unfortunately because BoringSSL itself is a C product, you end up with exactly the same problem that the SunEC provider has: a runtime dependency on a dynamic library.
While I generally don't love BouncyCastle (I am singularly convinced my dinky HTTPS-speaking CLI tool should not have a qTESLA implementation...) it is a pure-Java implementation and therefore "easy" for GraalVM to get working. For the rest of this ticket I'll be focusing on BouncyCastle.
To get replace the SunEC provider, two things need to happen:
-J-Djava.security.properties=java.security.overrides
, where java.security.overrides has lines likesecurity.provider.3=something
(3 is the default index of SunEC)Security/addProvider
orSecurity/insertProviderAt
.I created a Clojure program that just downloads
https://www.latacora.com
via a URL opener. I wrote [nscap][nscap], a tool to take a piece of code and run it in a Linux network namespace together withtcpdump
, enabling capture of just the packets from 1 process. I then analyze the resulting dumps withssldump
to see what TLS conversations actually take place. (Eventually I want to do this for macOS and Windows too but I'm not sure how to capture packets from one process across platforms; suggestions welcome.) Finally I summarize the results in the following table:The name column is "overrides+injects". Overrides are statements in java.security.overrides. Injects are parsed as follows: if there's an addbcprov, the code includes
(Security/addProvider (BouncyCastleProvider.))
, if there's an addbctls, the code includes(Security/addProvider (BouncyCastleJsseProvider.))
. In all cases, both providers are available on the classpath (but presumably, if they're not being statically loaded they're not otherwise in use, and possibly elided from the final image)."Successful download?" checks if I could find the
<title>
tag of the HTML page I'm downloading in the output. "SunEC warning?" shows if the runtime warns it couldn't find the SunEC library, which I'm using as a proxy to see if SunEC is being loaded at all. (SunEC|BC|BCJSSE) idx shows if a provider is in the security providers list at runtime and what index it's at. Best advertised handshake shows "ECDHE" if the client advertises ECDHE, otherwise DHE if it advertises that, otherwise nothing if only RSA suites are supported. This allows me to distinguish between "provider claims to support ECC, but doesn't actually do it" and "no provider with ECC is loaded at all". C->S/S->C records is the number of records sent back and forth (these are records in the TLS protocol sense), runtime exception is what it sounds like.My interpretation of these results is that if I want TLS to work reliably and I don't care about ECDHE I should just disable the SunEC provider via override, which was the conclusion of #951. Effectively, the builtin TLS support is fine, so bctls is a red herring; we just need an ECC provider implementation. BC does not actually work in any of these cases, which is evidenced by the fact that the table only shows DHE successful attempts.
I think the next step is to try and debug why the native image can't create an instance of bcprov.
Things that would be useful to me:
The text was updated successfully, but these errors were encountered: