What's new security features in Java 11?
Java 11 was released on Sep 25th, 2018. This is the first long-term support release produced under the six-month cadence release model. Besides a huge number of small improvements and bug fixes, the new release contains 17 major enhancements including:
- several updates in the Hotspot and garbage collectors
- new HTTP client
- Unicode 10
- deprecating Nashorn JavaScript Engine and Pack200 tool
- removing the Java EE and CORBA Modules
- local-variable syntax for Lambda parameters
- launch single-file source-code programs
- and finally several security features
Although all these features are pretty cool, let’s focus on security in this post.
Transport Layer Security (TLS) 1.3
TLS 1.3 specification was published in August 2018, and Java 11 already supports a minimal implementation of the new protocol. Here is what the JEP authors says:
The primary goal of this JEP is a minimal interoperable and compatible TLS 1.3 implementation. A minimal implementation should support:
- Protocol version negotiation
- TLS 1.3 full handshake
- TLS 1.3 session resumption
- TLS 1.3 key and iv update
- TLS 1.3 updated OCSP stapling
- TLS 1.3 backward compatibility mode
- TLS 1.3 required extensions and algorithms
- RSASSA-PSS signature algorithms (8146293)
There are no new APIs for TLS 1.3, the JEP only introduces several new constants:
- TLS protocol version name: TLSv1.3
- javax.net.ssl.SSLContext algorithm name: TLSv1.3
- TLS cipher suite names for TLS 1.3: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384.
Java Secure Sockets Extension (JSSE) has been significantly re-worked in Java 11. I used to work on security-libs in Java, and I can tell that was not an easy project. But nevertheless, Java security-libs team delivered TLS 1.3 implementation in Java 11. Great job!
Although there seem to be several bugs in the TLS 1.3 implementation which may affect interoperability with other protocol implementations, for example:
- NPE in SupportedGroupsExtension
- TLS 1.3 server fails if ClientHello doesn’t have pre_shared_key and psk_key_exchange_modes
- TLSv.1.3 interop problems with OpenSSL 1.1.1 when used on the client side with mutual auth
Most of the issues look to be already fixed in the development repository. Hope the fixes will be delivered in the next update release for Java 11.
If you’d like to try TLS 1.3 out with Java 11, here you can find an example of TLS 1.3 client and server on Java
ChaCha20 and Poly1305 Cryptographic Algorithms
There are several new features around TLS 1.3 implementation in JSSE. This is one of them. ChaCha20 is a stream cipher which is supposed to replace insecure RC4 cipher (disabled in Java), and Poly1305 is a message authentication code (MAC). ChaCha20 may be used in AEAD mode with the Poly1305 authenticator. This AEAD algorithm is usually called ChaCha20-Poly1305 and it’s also available in Java 11. Here is what the JEP author says:
Summary
Implement the ChaCha20 and ChaCha20-Poly1305 ciphers as specified in RFC 7539. ChaCha20 is a relatively new stream cipher that can replace the older, insecure RC4 stream cipher.
Goals
- Provide ChaCha20 and ChaCha20-Poly1305
Cipher
implementations. These algorithms will be implemented in the SunJCE provider.- Provide a
KeyGenerator
implementation that creates keys suitable for ChaCha20 and ChaCha20-Poly1305 algorithms.- Provide an
AlgorithmParameters
implementation for use with the ChaCha20-Poly1305 algorithm.
TLS 1.3. specification defines a couple of new cipher suites which use ChaCha20-Poly1305 algorithm but unfortunately supporting those new cipher suites was not a goal of this JEP. Hope we’ll get them in next Java releases.
You can find more details in JEP 329.
Key Agreement with Curve25519 and Curve448
This is another JEP related to TLS 1.3 implementation in Java. It adds a couple of new key exchange algorithms based on Curve25519 and Curve448 elliptic curves. Let’s take a look what the JEP author says:
Summary
Implement key agreement using Curve25519 and Curve448 as described in RFC 7748.
Goals
RFC 7748 defines a key agreement scheme that is more efficient and secure than the existing elliptic curve Diffie-Hellman (ECDH) scheme. The primary goal of this JEP is an API and an implementation for this standard. Additional implementation goals are:
- Develop a platform-independent, all-Java implementation with better performance than the existing ECC (native C) code at the same security strength.
- Ensure that the timing is independent of secrets, assuming the platform performs 64-bit integer addition/multiplication in constant time. In addition, the implementation will not branch on secrets. These properties are valuable for preventing side-channel attacks.
It’s great to see that the authors explicitly mentioned testing against side-channel attacks. These new algorithms are enabled in TLS 1.3 specification and even earlier protocol versions. More details in JEP 324.
Nest-Based Access Control
Java allows defining multiple classes in a single source file and even nested classes. But the Java compiler then produces a separate class file for each class. On the language layer, the classes should be able to access each others members (even private ones), but at runtime it’s prohibited by the JVM. To overcome this, the java compiler generates synthetic methods (they also are usually called bridge methods) which provide read-write access to the private fields. Such synthetic methods usually have package-level access.
Here is an example. Let’s consider the following Java code:
If we compile it with JDK 10 and run javap
, then we’ll get something like the following:
$ javac -d classes src/com/gypsyengineer/innerclass/field/*.java
$ javap -c -p classes/com/gypsyengineer/innerclass/field/Outer.class
Compiled from "Outer.java"
public class com.gypsyengineer.innerclass.field.Outer {
private int secret;
public com.gypsyengineer.innerclass.field.Outer();
Code:
0: aload_0
1: invokespecial #2 // Method java/lang/Object."":()V
4: aload_0
5: bipush 10
7: putfield #1 // Field secret:I
10: return
public void check();
Code:
0: aload_0
1: getfield #1 // Field secret:I
4: ifge 18
7: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #4 // String Oops
12: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: goto 26
18: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
21: ldc #6 // String Okay
23: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: return
static int access$002(com.gypsyengineer.innerclass.field.Outer, int);
Code:
0: aload_0
1: iload_1
2: dup_x1
3: putfield #1 // Field secret:I
6: ireturn
}
Note access$002
method which we didn’t explicitly define in the source code. This is a synthetic method which was added by the Java compiler, and which provides access to the private field. You can find more details in Accessing private fields with synthetic methods in Java
Java 11 relaxes access checks for such cases. Here is what the JEP authors say:
Introduce nests, an access-control context that aligns with the existing notion of nested types in the Java programming language. Nests allow classes that are logically part of the same code entity, but which are compiled to distinct class files, to access each other’s private members without the need for compilers to insert accessibility-broadening bridge methods.
If we compile the code above with JDK 11 and run javap
, then we’ll get the following:
$ javac -d classes src/com/gypsyengineer/innerclass/field/*.java
$ /home/asmotrakov/tools/jdk/jdk-11b28/bin/javap -c -p classes/com/gypsyengineer/innerclass/field/Outer.class
Compiled from "Outer.java"
public class com.gypsyengineer.innerclass.field.Outer {
private int secret;
public com.gypsyengineer.innerclass.field.Outer();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field secret:I
10: return
public void check();
Code:
0: aload_0
1: getfield #2 // Field secret:I
4: ifge 18
7: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #4 // String Oops
12: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: goto 26
18: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
21: ldc #6 // String Okay
23: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: return
}
The access$002
method is gone, but nevertheless the JVM successfully runs the code.
You can find more details in JEP 181. It’s a pretty big update in Java which affected the JVM specification, the Hotspot JVM, the Java compiler, Method Handles API, Reflection API, JVM TI, Java Instrumentation API, JDWP, JDI and even Pack200 (which is deprecated in Java 11 by the way). I hope this update doesn’t have any security side effects :)