diff --git a/SECURITY.md b/SECURITY.md
index 0b1c8f0b60..c330208395 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -4,9 +4,13 @@ gRPC supports a number of different mechanisms for asserting identity between an
# Transport Security (TLS)
-HTTP/2 over TLS mandates the use of [ALPN](https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05) to negotiate the use of the h2 protocol. ALPN is a fairly new standard and (where possible) gRPC also supports protocol negotiation via [NPN](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04) for systems that do not yet support ALPN.
+HTTP/2 over TLS mandates the use of [ALPN](https://tools.ietf.org/html/rfc7301)
+to negotiate the use of the h2 protocol and support for the GCM mode of AES.
-On Android, use the [Play Services Provider](#tls-on-android). For non-Android systems, use [OpenSSL](#tls-with-openssl).
+There are multiple options available, but on Android we recommend using the
+[Play Services Provider](#tls-on-android) and for non-Android systems we
+recommend [netty-tcnative with
+BoringSSL](#tls-with-netty-tcnative-on-boringssl).
## TLS on Android
@@ -42,100 +46,92 @@ import java.security.Security;
Security.insertProviderAt(Conscrypt.newProvider(), 1);
```
-## TLS with OpenSSL
+## TLS on non-Android
-This is currently the recommended approach for using gRPC over TLS (on non-Android systems).
+JDK versions prior to Java 9 do not support ALPN and are either missing AES GCM
+support or have 2% the performance of OpenSSL.
-The main benefits of using OpenSSL are:
+We recommend most users use grpc-netty-shaded, which includes netty-tcnative on
+BoringSSL. It includes pre-built libraries for 64 bit Windows, OS X, and 64 bit
+Linux. For 32 bit Windows, Conscrypt may be an option. For all other platforms,
+Java 9+ is required.
-1. **Speed**: In local testing, we've seen performance improvements of 3x over the JDK. GCM, which is used by the only cipher suite required by the HTTP/2 spec, is 10-500x faster.
-2. **Ciphers**: OpenSSL has its own ciphers and is not dependent on the limitations of the JDK. This allows supporting GCM on Java 7.
-3. **ALPN to NPN Fallback**: if the remote endpoint doesn't support ALPN.
-4. **Version Independence**: does not require using a different library version depending on the JDK update.
+For users of grpc-netty we recommend [netty-tcnative with
+BoringSSL](#tls-with-netty-tcnative-on-boringssl), although using the built-in
+JDK support in Java 9+, [Conscrypt](#tls-with-conscrypt), and [netty-tcnative
+with OpenSSL](#tls-with-netty-tcnative-on-openssl) are other valid options.
-Support for OpenSSL is only provided for the Netty transport via [netty-tcnative](https://github.com/netty/netty-tcnative), which is a fork of
-[Apache Tomcat's tcnative](http://tomcat.apache.org/native-doc/), a JNI wrapper around OpenSSL.
+[Netty TCNative](https://github.com/netty/netty-tcnative) is a fork of
+[Apache Tomcat's tcnative](http://tomcat.apache.org/native-doc/) and is a JNI
+wrapper around OpenSSL/BoringSSL/LibreSSL.
-### OpenSSL: Dynamic vs Static (which to use?)
+We recommend BoringSSL for its simplicitly and low occurence of security
+vulnerabilities relative to OpenSSL. BoringSSL is used by Conscrypt as well.
-As of version `1.1.33.Fork14`, netty-tcnative provides two options for usage: statically or dynamically linked. For simplification of initial setup,
-we recommend that users first look at `netty-tcnative-boringssl-static`, which is statically linked against BoringSSL and Apache APR. Using this artifact requires no extra installation and guarantees that ALPN and the ciphers required for
-HTTP/2 are available. In addition, starting with `1.1.33.Fork16` binaries for
-all supported platforms can be included at compile time and the correct binary
-for the platform can be selected at runtime.
+### TLS with netty-tcnative on BoringSSL
-Production systems, however, may require an easy upgrade path for OpenSSL security patches. In this case, relying on the statically linked artifact also implies waiting for the Netty team
-to release the new artifact to Maven Central, which can take some time. A better solution in this case is to use the dynamically linked `netty-tcnative` artifact, which allows the site administrator
-to easily upgrade OpenSSL in the standard way (e.g. apt-get) without relying on any new builds from Netty.
+Netty-tcnative with BoringSSL includes BoringSSL statically linked in the
+binary. This means the system's pre-installed TLS libraries will not be used.
+Production systems that have centralized upgrade agility in the face of
+security vulnerabilities may want to use [netty-tcnative on
+OpenSSL](#tls-with-netty-tcnative-on-openssl) instead.
-### OpenSSL: Statically Linked (netty-tcnative-boringssl-static)
+Users of grpc-netty-shaded will automatically use netty-tcnative with
+BoringSSL.
-This is the simplest way to configure the Netty transport for OpenSSL. You just need to add the appropriate `netty-tcnative-boringssl-static` artifact to your application's classpath.
+grpc-netty users will need to add the appropriate
+`netty-tcnative-boringssl-static` artifact to the application's classpath.
+Artifacts are available for 64 bit Windows, OS X, and 64 bit Linux.
-Artifacts are available on [Maven Central](http://repo1.maven.org/maven2/io/netty/netty-tcnative-boringssl-static/) for the following platforms:
-
-Maven Classifier | Description
----------------- | -----------
-windows-x86_64 | Windows distribution
-osx-x86_64 | Mac distribution
-linux-x86_64 | Linux distribution
-
-##### Getting netty-tcnative-boringssl-static from Maven
-
-In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-plugin) to help simplify the dependency.
+Depending on netty-tcnative-boringssl-static will include binaries for all
+supported platforms. For Maven:
```xml
-
io.netty
netty-tcnative-boringssl-static
- 2.0.20.Final
+ 2.0.20.Final
+ runtime
-
```
-##### Getting netty-tcnative-boringssl-static from Gradle
-
-Gradle you can use the [osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin), which is a wrapper around the os-maven-plugin.
+And for Gradle:
```gradle
-buildscript {
- repositories {
- mavenCentral()
- }
-}
-
dependencies {
- compile 'io.netty:netty-tcnative-boringssl-static:2.0.20.Final'
+ // See table for correct version
+ runtime 'io.netty:netty-tcnative-boringssl-static:2.0.20.Final'
}
```
-### OpenSSL: Dynamically Linked (netty-tcnative)
+For projects sensitive to binary size, specify the classifier for the precise
+platform you need: `windows-x86_64`, `osx-x86_64`, `linux-x86_64`. You can also
+use [os-maven-plugin](https://github.com/trustin/os-maven-plugin) or
+[osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin),
+to choose the classifier for the platform running the build.
-If for any reason you need to dynamically link against OpenSSL (e.g. you need control over the version of OpenSSL), you can instead use the `netty-tcnative` artifact.
+### TLS with netty-tcnative on OpenSSL
-Requirements:
+Using OpenSSL can have more initial configuration issues, but can be useful if
+your OS's OpenSSL version is recent and kept up-to-date with security fixes.
+OpenSSL is not included with tcnative, but instead is dynamically linked using
+your operating system's OpenSSL.
-1. [OpenSSL](https://www.openssl.org/) version >= 1.0.2 for ALPN support, or version >= 1.0.1 for NPN.
+To use OpenSSL you will use the `netty-tcnative` artifact. It requires:
+
+1. [OpenSSL](https://www.openssl.org/) version >= 1.0.2 for ALPN support.
2. [Apache APR library (libapr-1)](https://apr.apache.org/) version >= 1.5.2.
-3. [netty-tcnative](https://github.com/netty/netty-tcnative) version >= 1.1.33.Fork7 must be on classpath. Prior versions only supported NPN and only Fedora-derivatives were supported for Linux.
-Artifacts are available on [Maven Central](http://repo1.maven.org/maven2/io/netty/netty-tcnative/) for the following platforms:
+You must specify a classifier for the correct netty-tcnative binary:
+`windows-x86_64`, `osx-x86_64`, `linux-x86_64`, or `linux-x86_64-fedora`.
+Fedora derivatives use a different soname from other Linux distributations, so
+you must select the "fedora" version on those distributions.
-Classifier | Description
----------------- | -----------
-windows-x86_64 | Windows distribution
-osx-x86_64 | Mac distribution
-linux-x86_64 | Used for non-Fedora derivatives of Linux
-linux-x86_64-fedora | Used for Fedora derivatives
-
-On Linux it should be noted that OpenSSL uses a different soname for Fedora derivatives than other Linux releases. To work around this limitation, netty-tcnative deploys two separate versions for linux.
-
-##### Getting netty-tcnative from Maven
-
-In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-plugin) to help simplify the dependency.
+In Maven, you can use the
+[os-maven-plugin](https://github.com/trustin/os-maven-plugin) to help simplify
+the dependency.
```xml
@@ -143,8 +139,9 @@ In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-
io.netty
netty-tcnative
- 2.0.20.Final
+ 2.0.20.Final
${tcnative.classifier}
+ runtime
@@ -186,9 +183,8 @@ In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-
```
-##### Getting netty-tcnative from Gradle
-
-Gradle you can use the [osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin), which is a wrapper around the os-maven-plugin.
+And in Gradle you can use the
+[osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin).
```gradle
buildscript {
@@ -211,43 +207,50 @@ if (osdetector.os == "linux" && osdetector.release.isLike("fedora")) {
}
dependencies {
- compile 'io.netty:netty-tcnative:2.0.20.Final:' + tcnative_classifier
+ runtime 'io.netty:netty-tcnative:2.0.20.Final:' + tcnative_classifier
}
```
-## TLS with JDK (Jetty ALPN/NPN)
+### TLS with Conscrypt
-**WARNING: DON'T DO THIS!!**
+[Conscrypt](https://conscrypt.org) provides an implementation of the JSSE
+security APIs based on BoringSSL. Pre-built binaries are available for 32 and
+64 bit Windows, OS X, and 64 bit Linux.
-*For non-Android systems, the recommended approach is to use [OpenSSL](#tls-with-openssl). Using the JDK for ALPN is generally much slower and may not support the necessary ciphers for HTTP2.*
+Depend on `conscrypt-openjdk-uber` for binaries of all supported JRE platforms.
+For projects sensitive to binary size, depend on `conscrypt-openjdk` and
+specify the appropriate classifier. `os-maven-plugin` and
+`osdetector-gradle-plugin` may also be used. See the documentation for
+[netty-tcnative-boringssl-static](#tls-with-netty-tcnative-on-boringssl) for
+example usage of the plugins.
-*Jetty ALPN brings its own baggage in that the Java bootclasspath needs to be modified, which may not be an option for some environments. In addition, a specific version of Jetty ALPN has to be used for a given version of the JRE. If the versions don't match the negotiation will fail, but you won't really know why. And since there is such a tight coupling between Jetty ALPN and the JRE, there are no guarantees that Jetty ALPN will support every JRE out in the wild.*
+Generally you will "install" Conscrypt before use, for gRPC to find.
-*The moral of the story is: Don't use the JDK for ALPN! But if you absolutely have to, here's how you do it... :)*
+```java
+import org.conscrypt.Conscrypt;
+import java.security.Security;
+...
----
-
-If not using the Netty transport (or you are unable to use OpenSSL for some reason) another alternative is to use the JDK for TLS.
-
-No standard Java release has built-in support for ALPN today ([there is a tracking issue](https://bugs.openjdk.java.net/browse/JDK-8051498) so go upvote it!) so we need to use the [Jetty-ALPN](https://github.com/jetty-project/jetty-alpn) (or [Jetty-NPN](https://github.com/jetty-project/jetty-npn) if on Java < 8) bootclasspath extension for OpenJDK. To do this, add an `Xbootclasspath` JVM option referencing the path to the Jetty `alpn-boot` jar.
-
-```sh
-java -Xbootclasspath/p:/path/to/jetty/alpn/extension.jar ...
+// Somewhere in main()
+Security.insertProviderAt(Conscrypt.newProvider(), 1);
```
-Note that you must use the [release of the Jetty-ALPN jar](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-versions) specific to the version of Java you are using. However, you can use the JVM agent [Jetty-ALPN-Agent](https://github.com/jetty-project/jetty-alpn-agent) to load the correct Jetty `alpn-boot` jar file for the current Java version. To do this, instead of adding an `Xbootclasspath` option, add a `javaagent` JVM option referencing the path to the Jetty `alpn-agent` jar.
+### TLS with Jetty ALPN
-```sh
-java -javaagent:/path/to/jetty-alpn-agent.jar ...
-```
+**Please do not use Jetty ALPN**
-### JDK Ciphers
+gRPC historically supported Jetty ALPN for ALPN on Java 8. While functional, it
+suffers from poor performance and breakages when the JRE is upgraded.
+When mis-matched to the JRE version, it can also produce unpredictable errors
+that are hard to diagnose. When using it, it became common practice that any
+time we saw a TLS failure that made no sense we would blame a Jetty ALPN/JRE
+version mismatch and we were overwhelmingly correct. The Jetty ALPN agent makes
+it much easier to use, but we still strongly discourage Jetty ALPN's use.
-Java 7 does not support [the cipher suites recommended](https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-9.2.2) by the HTTP2 specification. To address this we suggest servers use Java 8 where possible or use an alternative JCE implementation such as [Bouncy Castle](https://www.bouncycastle.org/java.html). If this is not practical it is possible to use other ciphers but you need to ensure that the services you intend to call have [allowed out-of-spec ciphers](https://github.com/grpc/grpc/issues/681) and have evaluated the security risks of doing so.
+When using Jetty ALPN with Java 8, realize that performance will be 2-10% that
+of the other options due to a slow AES GCM implementation in Java.
-Users should be aware that GCM is [_very_ slow (1 MB/s)](https://bugzilla.redhat.com/show_bug.cgi?id=1135504) before Java 8u60. With Java 8u60 GCM is 10x faster (10-20 MB/s), but that is still slow compared to OpenSSL (~200 MB/s), especially with AES-NI support (~1 GB/s). GCM cipher suites are the only suites available that comply with HTTP2's cipher requirements.
-
-### Configuring Jetty ALPN in Web Containers
+#### Configuring Jetty ALPN in Web Containers
Some web containers, such as [Jetty](http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html) restrict access to server classes for web applications. A gRPC client running within such a container must be properly configured to allow access to the ALPN classes. In Jetty, this is done by including a `WEB-INF/jetty-env.xml` file containing the following: