Merge upstream master

No significant changes, just some new tests and bug fixes.

Fixes: 120477291
Test: cts -m CtsLibcoreTestCases
Change-Id: I61edcb1c79ebcd7153baaae1da85ead06b97a3ec
diff --git a/README.md b/README.md
index 7833d96..a6ae3f6 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@
 <dependency>
   <groupId>org.conscrypt</groupId>
   <artifactId>conscrypt-openjdk</artifactId>
-  <version>1.4.0</version>
+  <version>1.4.1</version>
   <classifier>${os.detected.classifier}</classifier>
 </dependency>
 ```
@@ -91,7 +91,7 @@
 apply plugin: "com.google.osdetector"
 
 dependencies {
-  compile 'org.conscrypt:conscrypt-openjdk:1.4.0:' + osdetector.classifier
+  compile 'org.conscrypt:conscrypt-openjdk:1.4.1:' + osdetector.classifier
 }
 ```
 
@@ -109,14 +109,14 @@
 <dependency>
   <groupId>org.conscrypt</groupId>
   <artifactId>conscrypt-openjdk-uber</artifactId>
-  <version>1.4.0</version>
+  <version>1.4.1</version>
 </dependency>
 ```
 
 ##### Gradle
 ```gradle
 dependencies {
-  compile 'org.conscrypt:conscrypt-openjdk-uber:1.4.0'
+  compile 'org.conscrypt:conscrypt-openjdk-uber:1.4.1'
 }
 ```
 
@@ -129,7 +129,7 @@
 
 ```gradle
 dependencies {
-  compile 'org.conscrypt:conscrypt-android:1.4.0'
+  compile 'org.conscrypt:conscrypt-android:1.4.1'
 }
 ```
 
diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java
index 46a0c02..93e1b7b 100644
--- a/android/src/main/java/org/conscrypt/Platform.java
+++ b/android/src/main/java/org/conscrypt/Platform.java
@@ -542,19 +542,6 @@
         }
     }
 
-    /**
-     * Returns true if the supplied hostname is an literal IP address.
-     */
-    public static boolean isLiteralIpAddress(String hostname) {
-        try {
-            Method m_isNumeric = InetAddress.class.getMethod("isNumeric", String.class);
-            return (Boolean) m_isNumeric.invoke(null, hostname);
-        } catch (Exception ignored) {
-        }
-
-        return AddressUtils.isLiteralIpAddress(hostname);
-    }
-
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         // For now, don't wrap on Android.
         return engine;
diff --git a/appveyor.yml b/appveyor.yml
index bc64b28..c7e2dcf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,8 +7,6 @@
   NINJA_URL: "https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip"
   CMAKE_URL: "https://cmake.org/files/v3.11/cmake-3.11.1-win32-x86.zip"
   MSVC_HOME: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community"
-  YASM_URL: "http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win32.exe"
-  YASM_SHA256: "db8ef9348ae858354cee4cc2f99e0f36de8a47a121de4cfeea5a16d45dd5ac1b"
 
 clone_folder: "C:\\projects\\conscrypt"
 shallow_clone: true
@@ -44,11 +42,8 @@
   - set PATH=C:\cmake\bin;%PATH%
   - cmake --version
 
-  # Install yasm
-  - mkdir C:\yasm
-  - appveyor DownloadFile %YASM_URL% -FileName C:\yasm\yasm.exe
-  - ps: if ((Get-FileHash C:\yasm\yasm.exe -Algorithm SHA256).Hash.ToLower() -ne $env:YASM_SHA256) { Throw "Yasm hash mismatch" }
-  - set PATH=C:\yasm;%PATH%
+  # Install NASM
+  - choco install -y --allow-empty-checksums nasm
 
   # Install Go for BoringSSL compile (embedding test data)
   - choco install -y --allow-empty-checksums golang
diff --git a/common/src/main/java/org/conscrypt/AddressUtils.java b/common/src/main/java/org/conscrypt/AddressUtils.java
index f480884..57a00b1 100644
--- a/common/src/main/java/org/conscrypt/AddressUtils.java
+++ b/common/src/main/java/org/conscrypt/AddressUtils.java
@@ -43,7 +43,7 @@
         // Must be a FQDN that does not have a trailing dot.
         return (sniHostname.equalsIgnoreCase("localhost")
                     || sniHostname.indexOf('.') != -1)
-                && !Platform.isLiteralIpAddress(sniHostname)
+                && !isLiteralIpAddress(sniHostname)
                 && !sniHostname.endsWith(".")
                 && sniHostname.indexOf('\0') == -1;
     }
diff --git a/common/src/main/java/org/conscrypt/ConscryptEngine.java b/common/src/main/java/org/conscrypt/ConscryptEngine.java
index 1974e2d..a56e7fd 100644
--- a/common/src/main/java/org/conscrypt/ConscryptEngine.java
+++ b/common/src/main/java/org/conscrypt/ConscryptEngine.java
@@ -145,7 +145,7 @@
     /**
      * Set during startHandshake.
      */
-    private final ActiveSession activeSession;
+    private ActiveSession activeSession;
 
     /**
      * A snapshot of the active session when the engine was closed.
@@ -184,7 +184,6 @@
         peerInfoProvider = PeerInfoProvider.nullProvider();
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     ConscryptEngine(String host, int port, SSLParametersImpl sslParameters) {
@@ -192,7 +191,6 @@
         this.peerInfoProvider = PeerInfoProvider.forHostAndPort(host, port);
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     ConscryptEngine(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider) {
@@ -200,7 +198,6 @@
         this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider");
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     private static NativeSsl newSsl(SSLParametersImpl sslParameters, ConscryptEngine engine) {
@@ -464,10 +461,15 @@
             if (state == STATE_CLOSED || state == STATE_CLOSED_INBOUND) {
                 return;
             }
-            if (isOutboundDone()) {
-                closeAndFreeResources();
+            if (isHandshakeStarted()) {
+                if (isOutboundDone()) {
+                    closeAndFreeResources();
+                } else {
+                    transitionTo(STATE_CLOSED_INBOUND);
+                }
             } else {
-                transitionTo(STATE_CLOSED_INBOUND);
+                // Never started the handshake. Just close now.
+                closeAndFreeResources();
             }
         }
     }
@@ -1819,10 +1821,11 @@
         switch (newState) {
             case STATE_HANDSHAKE_STARTED: {
                 handshakeFinished = false;
+                activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
                 break;
             }
             case STATE_CLOSED: {
-                if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED ) {
+                if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED) {
                     closedSession = new SessionSnapshot(activeSession);
                 }
                 break;
diff --git a/common/src/main/java/org/conscrypt/EvpMdRef.java b/common/src/main/java/org/conscrypt/EvpMdRef.java
index 633b088..7dab357 100644
--- a/common/src/main/java/org/conscrypt/EvpMdRef.java
+++ b/common/src/main/java/org/conscrypt/EvpMdRef.java
@@ -32,18 +32,20 @@
      */
     static String getJcaDigestAlgorithmStandardName(String algorithm) {
         String algorithmUpper = algorithm.toUpperCase(Locale.US);
-        if ((SHA256.JCA_NAME.equals(algorithmUpper)) || (SHA256.OID.equals(algorithmUpper))) {
+        if (SHA256.JCA_NAME.equals(algorithmUpper)
+            || SHA256.OID.equals(algorithmUpper)) {
             return SHA256.JCA_NAME;
-        } else if ((SHA512.JCA_NAME.equals(algorithmUpper))
-                || (SHA512.OID.equals(algorithmUpper))) {
+        } else if (SHA512.JCA_NAME.equals(algorithmUpper)
+                || SHA512.OID.equals(algorithmUpper)) {
             return SHA512.JCA_NAME;
-        } else if ((SHA1.JCA_NAME.equals(algorithmUpper)) || (SHA1.OID.equals(algorithmUpper))) {
+        } else if (SHA1.JCA_NAME.equals(algorithmUpper)
+                || SHA1.OID.equals(algorithmUpper)) {
             return SHA1.JCA_NAME;
-        } else if ((SHA384.JCA_NAME.equals(algorithmUpper))
-                || (SHA384.OID.equals(algorithmUpper))) {
+        } else if (SHA384.JCA_NAME.equals(algorithmUpper)
+                || SHA384.OID.equals(algorithmUpper)) {
             return SHA384.JCA_NAME;
-        } else if ((SHA224.JCA_NAME.equals(algorithmUpper))
-                || (SHA224.OID.equals(algorithmUpper))) {
+        } else if (SHA224.JCA_NAME.equals(algorithmUpper)
+                || SHA224.OID.equals(algorithmUpper)) {
             return SHA224.JCA_NAME;
         } else {
             return null;
diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java
index 053b4e5..a4f9c74 100644
--- a/common/src/main/java/org/conscrypt/NativeSsl.java
+++ b/common/src/main/java/org/conscrypt/NativeSsl.java
@@ -434,7 +434,7 @@
         if (pskKeyManager != null) {
             boolean pskEnabled = false;
             for (String enabledCipherSuite : parameters.enabledCipherSuites) {
-                if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
+                if ((enabledCipherSuite != null) && enabledCipherSuite.contains("PSK")) {
                     pskEnabled = true;
                     break;
                 }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java b/common/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java
index f1a0811..a21b5b5 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLBIOInputStream.java
@@ -73,4 +73,35 @@
 
         return offset;
     }
+
+    @Override
+    public int read(byte[] buffer) throws IOException {
+        return read(buffer, 0, buffer.length);
+    }
+
+    // InputStream.read() is allowed to return less than len bytes, and the socket InputStreams
+    // that are used with this class typically do so when the length requested is more than what
+    // is already buffered, but some users of BoringSSL's BIO APIs expect that any read call either
+    // fills the buffer completely, fails, or reaches EOF.  We patch over this difference by
+    // repeatedly calling super.read() until it indicates EOF or we fill the buffer.
+    @Override
+    public int read(byte[] buffer, int offset, int len) throws IOException {
+        if (offset < 0 || len < 0 || len > buffer.length - offset) {
+            throw new IndexOutOfBoundsException("Invalid bounds");
+        }
+        if (len == 0) {
+            return 0;
+        }
+        int totalRead = 0;
+        int read;
+        do {
+            read = super.read(buffer, offset + totalRead, len - totalRead - offset);
+            if (read == -1) {
+                break;
+            }
+            totalRead += read;
+        } while (offset + totalRead < len);
+
+        return totalRead == 0 ? -1 : totalRead;
+    }
 }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java b/common/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java
index 0a3ad37..83d6487 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLECKeyFactory.java
@@ -177,7 +177,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
+        } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
@@ -187,7 +187,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
+        } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java b/common/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java
index 18d9d5b..c78dfe8 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAKeyFactory.java
@@ -227,7 +227,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
+        } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
@@ -237,7 +237,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
+        } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
index ffc672f..8e9fb59 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
@@ -99,7 +99,7 @@
         return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
     }
 
-    private void ensureReadParams() {
+    private synchronized void ensureReadParams() {
         if (fetchedParams) {
             return;
         }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLSignature.java b/common/src/main/java/org/conscrypt/OpenSSLSignature.java
index 9b1f605..105bf0f 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLSignature.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLSignature.java
@@ -391,8 +391,8 @@
             }
 
             String specMgfAlgorithm = spec.getMGFAlgorithm();
-            if ((!EvpMdRef.MGF1_ALGORITHM_NAME.equalsIgnoreCase(specMgfAlgorithm))
-                    && (!EvpMdRef.MGF1_OID.equals(specMgfAlgorithm))) {
+            if (!EvpMdRef.MGF1_ALGORITHM_NAME.equalsIgnoreCase(specMgfAlgorithm)
+                    && !EvpMdRef.MGF1_OID.equals(specMgfAlgorithm)) {
                 throw new InvalidAlgorithmParameterException(
                         "Unsupported MGF algorithm: " + specMgfAlgorithm + ". Only "
                                 + EvpMdRef.MGF1_ALGORITHM_NAME + " supported");
diff --git a/libcore-stub/src/main/java/libcore/java/security/StandardNames.java b/libcore-stub/src/main/java/libcore/java/security/StandardNames.java
index 05d1c30..fd8dac6 100644
--- a/libcore-stub/src/main/java/libcore/java/security/StandardNames.java
+++ b/libcore-stub/src/main/java/libcore/java/security/StandardNames.java
@@ -69,13 +69,13 @@
 public final class StandardNames {
     public static final boolean IS_RI =
             !"Dalvik Core Library".equals(System.getProperty("java.specification.name"));
-    public static final String JSSE_PROVIDER_NAME = (IS_RI) ? "Conscrypt" : "AndroidOpenSSL";
-    public static final String SECURITY_PROVIDER_NAME = (IS_RI) ? "SUN" : "BC";
+    public static final String JSSE_PROVIDER_NAME = IS_RI ? "Conscrypt" : "AndroidOpenSSL";
+    public static final String SECURITY_PROVIDER_NAME = IS_RI ? "SUN" : "BC";
 
-    public static final String KEY_MANAGER_FACTORY_DEFAULT = (IS_RI) ? "SunX509" : "PKIX";
+    public static final String KEY_MANAGER_FACTORY_DEFAULT = IS_RI ? "SunX509" : "PKIX";
     public static final String TRUST_MANAGER_FACTORY_DEFAULT = "PKIX";
 
-    public static final String KEY_STORE_ALGORITHM = (IS_RI) ? "JKS" : "BKS";
+    public static final String KEY_STORE_ALGORITHM = IS_RI ? "JKS" : "BKS";
 
     /**
      * RFC 5746's Signaling Cipher Suite Value to indicate a request for secure renegotiation
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
index b1c5f0d..520e3a0 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -324,7 +324,7 @@
                 continue;
             }
             if ("EC".equals(algorithm)
-                    && ("SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName()))
+                    && "SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())
                     && keySize == 224) {
                 // TODO(flooey): Remove when we stop supporting Java 6
                 // This Sun provider doesn't support 224-bit EC keys
@@ -343,8 +343,8 @@
             test_KeyPair(kpg, kpg.generateKeyPair());
         }
 
-        if (("EC".equals(algorithm)) || ("ECDH".equals(algorithm))
-                || ("ECDSA".equals(algorithm))) {
+        if ("EC".equals(algorithm) || "ECDH".equals(algorithm)
+                || "ECDSA".equals(algorithm)) {
             if ("SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())) {
                 // SunPKCS11 doesn't support some of the named curves that we expect, so it
                 // fails.  Skip it.
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
index c9c7b79..ebb94b4 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/SignatureTest.java
@@ -169,8 +169,8 @@
             kpAlgorithm = "EC";
         } else if (sigAlgorithmUpperCase.endsWith("DSA")) {
             kpAlgorithm = "DSA";
-        } else if ((sigAlgorithmUpperCase.endsWith("RSA"))
-                || (sigAlgorithmUpperCase.endsWith("RSA/PSS"))) {
+        } else if (sigAlgorithmUpperCase.endsWith("RSA")
+                || sigAlgorithmUpperCase.endsWith("RSA/PSS")) {
             kpAlgorithm = "RSA";
         } else {
             throw new Exception("Unknown KeyPair algorithm for Signature algorithm "
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
index 9f5d515..75bd1ff 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -25,6 +25,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
@@ -61,6 +62,7 @@
 import org.bouncycastle.x509.X509V3CertificateGenerator;
 import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
 import org.conscrypt.Conscrypt;
+import org.conscrypt.TestUtils;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -194,6 +196,23 @@
             + "AAAAAAAA\n"
             + "-----END CERTIFICATE-----";
 
+    private static final String VALID_CERTIFICATE_DER_BASE64 =
+        "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQG"
+        + "EwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhh"
+        + "d3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0xMTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVT"
+        + "MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApH"
+        + "b29nbGUgSW5jMRcwFQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw"
+        + "gYkCgYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jNgtXj9xVo"
+        + "RaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L05vuuWciKh0R73mkszeK"
+        + "9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAMBgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0w"
+        + "K6ApoCeGJWh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYI"
+        + "KwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzAB"
+        + "hhZodHRwOi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0ZS5j"
+        + "b20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUFAAOBgQCfQ89bxFAp"
+        + "sb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5u2ONgJd8IyAPkU0Wueru9G2Jysa9"
+        + "zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqA"
+        + "ibAxWEEHXw==";
+
     @Test
     public void test_generateCertificate() throws Exception {
         Provider[] providers = Security.getProviders("CertificateFactory.X509");
@@ -205,6 +224,7 @@
                 test_generateCertificate_InputStream_Empty(cf);
                 test_generateCertificate_InputStream_InvalidStart_Failure(cf);
                 test_generateCertificate_AnyLineLength_Success(cf);
+                test_generateCertificate_PartialInput(cf);
             } catch (Throwable e) {
                 throw new Exception("Problem testing " + p.getName(), e);
             }
@@ -224,6 +244,12 @@
             assertNotNull(c);
         }
 
+        {
+            byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+            Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+            assertNotNull(c);
+        }
+
         try {
             byte[] invalid = INVALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
             cf.generateCertificate(new ByteArrayInputStream(invalid));
@@ -246,6 +272,7 @@
             assertTrue((c == null) && cf.getProvider().getName().equals("BC"));
         } catch (CertificateException expected) {
         }
+
     }
 
     /*
@@ -409,6 +436,43 @@
         }
     }
 
+    /**
+     * An InputStream that only returns two bytes at a time, no matter how many were requested.
+     */
+    private static class SlowInputStream extends FilterInputStream {
+        protected SlowInputStream(InputStream inputStream) {
+            super(inputStream);
+        }
+
+        @Override
+        public int read(byte[] buffer) throws IOException {
+            if (buffer.length < 2) {
+                return super.read(buffer);
+            }
+            return super.read(buffer, 0, 2);
+        }
+
+        @Override
+        public int read(byte[] buffer, int offset, int len) throws IOException {
+            if (len < 2) {
+                return super.read(buffer, offset, len);
+            }
+            return super.read(buffer, offset, 2);
+        }
+    }
+
+    // Test that certificates are decoded properly even if the InputStream is unhelpful and only
+    // returns partial inputs on basically every request.
+    private void test_generateCertificate_PartialInput(CertificateFactory cf) throws Exception {
+        byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+        Certificate c = cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+        assertNotNull(c);
+
+        valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+        c = cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+        assertNotNull(c);
+    }
+
     /* CertPath tests */
     @Test
     public void testGenerateCertPath() throws Exception {
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
index 58c054c..4437755 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/crypto/CipherTest.java
@@ -110,13 +110,13 @@
     /** GCM tag size used for tests. */
     private static final int GCM_TAG_SIZE_BITS = 96;
 
-    private static final String[] RSA_PROVIDERS = ((StandardNames.IS_RI)
+    private static final String[] RSA_PROVIDERS = StandardNames.IS_RI
         ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
-        : new String[] { "BC" , StandardNames.JSSE_PROVIDER_NAME });
+        : new String[] { "BC" , StandardNames.JSSE_PROVIDER_NAME };
 
-    private static final String[] AES_PROVIDERS = ((StandardNames.IS_RI)
+    private static final String[] AES_PROVIDERS = StandardNames.IS_RI
         ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
-        : new String[] { "BC", StandardNames.JSSE_PROVIDER_NAME });
+        : new String[] { "BC", StandardNames.JSSE_PROVIDER_NAME };
 
     private static boolean isSupported(String algorithm, String provider) {
         if (algorithm.equals("RC2")) {
@@ -1391,7 +1391,7 @@
                     Arrays.toString(
                             ((PSource.PSpecified) expectedOaepSpec.getPSource()).getValue()),
                     Arrays.toString(
-                            (((PSource.PSpecified) actualOaepSpec.getPSource()).getValue())));
+                            ((PSource.PSpecified) actualOaepSpec.getPSource()).getValue()));
         } else {
             fail("Unknown PSource type");
         }
@@ -4589,14 +4589,14 @@
             if (c.contains("/CBC/")) {
                 cipher.init(Cipher.DECRYPT_MODE,
                         new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
-                                (c.startsWith("AES/")) ? "AES" : "DESEDE"),
+                                c.startsWith("AES/") ? "AES" : "DESEDE"),
                         new IvParameterSpec(
-                                ("01234567" + ((c.startsWith("AES/")) ? "89012345" : ""))
+                                ("01234567" + (c.startsWith("AES/") ? "89012345" : ""))
                                         .getBytes(StandardCharsets.US_ASCII)));
             } else {
                 cipher.init(Cipher.DECRYPT_MODE,
                         new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
-                                (c.startsWith("AES/")) ? "AES" : "DESEDE"));
+                                c.startsWith("AES/") ? "AES" : "DESEDE"));
             }
 
             byte[] buffer = new byte[0];
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
index 39ba9ed..a0d642e 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
@@ -23,7 +23,7 @@
 import static org.junit.Assert.fail;
 
 import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore.Builder;
+import java.security.KeyStore;
 import java.security.KeyStore.PasswordProtection;
 import java.security.KeyStore.PrivateKeyEntry;
 import java.security.PrivateKey;
@@ -119,7 +119,7 @@
 
         // init with KeyStoreBuilderParameters ManagerFactoryParameters
         PasswordProtection pp = new PasswordProtection(getTestKeyStore().storePassword);
-        Builder builder = Builder.newInstance(getTestKeyStore().keyStore, pp);
+        KeyStore.Builder builder = KeyStore.Builder.newInstance(getTestKeyStore().keyStore, pp);
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
         if (supportsManagerFactoryParameters(kmf.getAlgorithm())) {
             kmf.init(ksbp);
@@ -195,8 +195,11 @@
             }
         }
 
-        String a = km.chooseClientAlias(keyTypes, null, null);
-        test_X509KeyManager_alias(km, a, null, true, empty);
+        String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+        for (String[] keyList : rotatedTypes) {
+            String alias = km.chooseClientAlias(keyList, null, null);
+            test_X509KeyManager_alias(km, alias, null, true, empty);
+        }
 
         for (String keyType : keyTypes) {
             String[] array = new String[] {keyType};
@@ -215,8 +218,12 @@
     private void test_X509ExtendedKeyManager(
             X509ExtendedKeyManager km, boolean empty, String algorithm) throws Exception {
         String[] keyTypes = keyTypes(algorithm);
-        String a = km.chooseEngineClientAlias(keyTypes, null, null);
-        test_X509KeyManager_alias(km, a, null, true, empty);
+        String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+        for (String[] keyList : rotatedTypes) {
+            String alias = km.chooseEngineClientAlias(keyList, null, null);
+            test_X509KeyManager_alias(km, alias, null, true, empty);
+        }
+
         for (String keyType : keyTypes) {
             String[] array = new String[] {keyType};
             String alias = km.chooseEngineClientAlias(array, null, null);
@@ -228,6 +235,30 @@
         }
     }
 
+    // Filters null or empty values from a String array and returns a new array with the results.
+    private static String[] nonEmpty(String[] input) {
+        String[] nonEmpty = new String[input.length];
+        int size = 0;
+        for (String keyType : input) {
+            if (keyType != null && !keyType.isEmpty()) {
+                nonEmpty[size++] = keyType;
+            }
+        }
+        return Arrays.copyOfRange(nonEmpty, 0, size);
+    }
+
+    // Generates an array of arrays of all the rotational permutations of its input.
+    private static String[][] rotate(String[] input) {
+        int size = input.length;
+        String[][] result = new String[size][size];
+        for (int i = 0; i < size; i++) {
+            for (int j = 0; j < size; j++) {
+                result[i][j] = input[(i + j) % size];
+            }
+        }
+        return result;
+    }
+
     private void test_X509KeyManager_alias(X509KeyManager km, String alias, String keyType,
             boolean many, boolean empty) throws Exception {
         if (empty || (!many && (keyType == null || keyType.isEmpty()))) {
@@ -236,8 +267,7 @@
             assertNull(keyType, km.getPrivateKey(alias));
             return;
         }
-        assertNotNull(keyType, alias);
-
+        assertNotNull(alias);
         X509Certificate[] certificateChain = km.getCertificateChain(alias);
         PrivateKey privateKey = km.getPrivateKey(alias);
 
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
index fa8650e..c44f9c1 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
@@ -22,7 +22,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
-import java.security.KeyStore.Builder;
+import java.security.KeyStore;
 import java.security.KeyStore.PasswordProtection;
 import java.util.Arrays;
 import java.util.List;
@@ -53,7 +53,7 @@
         // Objects.requireNonNull was added
         assumeObjectsAvailable();
         try {
-            new KeyStoreBuilderParameters((Builder) null);
+            new KeyStoreBuilderParameters((KeyStore.Builder) null);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -62,7 +62,7 @@
     @Test
     public void test_init_Builder() {
         TestKeyStore testKeyStore = TestKeyStore.getClient();
-        Builder builder = Builder.newInstance(
+        KeyStore.Builder builder = KeyStore.Builder.newInstance(
                 testKeyStore.keyStore, new PasswordProtection(testKeyStore.storePassword));
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
         assertNotNull(ksbp);
@@ -74,7 +74,7 @@
     @Test
     public void test_init_List_null() {
         try {
-            new KeyStoreBuilderParameters((List<Builder>) null);
+            new KeyStoreBuilderParameters((List<KeyStore.Builder>) null);
             fail();
         } catch (NullPointerException expected) {
             // Ignored.
@@ -85,12 +85,12 @@
     public void test_init_List() {
         TestKeyStore testKeyStore1 = TestKeyStore.getClient();
         TestKeyStore testKeyStore2 = TestKeyStore.getServer();
-        Builder builder1 = Builder.newInstance(
+        KeyStore.Builder builder1 = KeyStore.Builder.newInstance(
                 testKeyStore1.keyStore, new PasswordProtection(testKeyStore1.storePassword));
-        Builder builder2 = Builder.newInstance(
+        KeyStore.Builder builder2 = KeyStore.Builder.newInstance(
                 testKeyStore2.keyStore, new PasswordProtection(testKeyStore2.storePassword));
 
-        List<Builder> list = Arrays.asList(builder1, builder2);
+        List<KeyStore.Builder> list = Arrays.asList(builder1, builder2);
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(list);
         assertNotNull(ksbp);
         assertNotNull(ksbp.getParameters());
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
index 7e9f7fc..e41bdf2 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
@@ -174,10 +174,10 @@
             context.init(null, null, null);
 
             StandardNames.assertSSLContextEnabledProtocols(
-                    tlsVersion, ((SSLSocket) (context.getSocketFactory().createSocket()))
+                    tlsVersion, ((SSLSocket) context.getSocketFactory().createSocket())
                                         .getEnabledProtocols());
             StandardNames.assertSSLContextEnabledProtocols(tlsVersion,
-                    ((SSLServerSocket) (context.getServerSocketFactory().createServerSocket()))
+                    ((SSLServerSocket) context.getServerSocketFactory().createServerSocket())
                             .getEnabledProtocols());
             StandardNames.assertSSLContextEnabledProtocols(
                     tlsVersion, context.getDefaultSSLParameters().getProtocols());
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
index 63dc7fe..50e6300 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -248,8 +248,8 @@
                 boolean serverAuthenticatedUsingPublicKey = true;
                 if (cipherSuite.contains("_anon_")) {
                     serverAuthenticatedUsingPublicKey = false;
-                } else if ((cipherSuite.startsWith("TLS_PSK_"))
-                        || (cipherSuite.startsWith("TLS_ECDHE_PSK_"))) {
+                } else if (cipherSuite.startsWith("TLS_PSK_")
+                        || cipherSuite.startsWith("TLS_ECDHE_PSK_")) {
                     serverAuthenticatedUsingPublicKey = false;
                 }
                 if (serverAuthenticatedUsingPublicKey) {
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
index 8a25e78..4756104 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
@@ -664,9 +664,9 @@
                 && !b.isInboundDone() && !a.isOutboundDone() && !b.isOutboundDone());
     }
 
-    // Assumes that the negotiated connection will be
+    // Assumes that the negotiated connection will be TLS 1.2
     private void assumeTlsV1_2Connection() {
-        assumeTrue("TLSv1.2.".equals(negotiatedVersion()));
+        assumeTrue("TLSv1.2".equals(negotiatedVersion()));
     }
 
     /**
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
index d3cd174..f4ca0cf 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
@@ -329,7 +329,7 @@
     }
 
     private int expectedSslSessionCacheTimeout(TestSSLContext c) {
-        return (isConscrypt(c.serverContext.getProvider())) ? 8 * 3600 : 24 * 3600;
+        return isConscrypt(c.serverContext.getProvider()) ? 8 * 3600 : 24 * 3600;
     }
 
     private static int numSessions(SSLSessionContext s) {
diff --git a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
index 36d1796..a80c3dc 100644
--- a/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
+++ b/openjdk-integ-tests/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -1581,8 +1581,8 @@
         server.getOutputStream().write(42);
         assertEquals(42, handshakeFuture.get().intValue());
 
-        final Socket toRead = (readUnderlying) ? underlying : clientWrapping;
-        final Socket toClose = (closeUnderlying) ? underlying : clientWrapping;
+        final Socket toRead = readUnderlying ? underlying : clientWrapping;
+        final Socket toClose = closeUnderlying ? underlying : clientWrapping;
 
         // Schedule the socket to be closed in 1 second.
         Future<Void> future = runAsync(new Callable<Void>() {
@@ -2101,6 +2101,12 @@
                     || cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)) {
                 continue;
             }
+            /*
+             * tls_unique only works on 1.2, so skip TLS 1.3 cipher suites.
+             */
+            if (StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+                continue;
+            }
             TestSSLSocketPair pair = TestSSLSocketPair.create(c);
             try {
                 String[] cipherSuites =
@@ -2277,9 +2283,9 @@
         }
     }
 
-    // Assumes that the negotiated connection will be
+    // Assumes that the negotiated connection will be TLS 1.2
     private void assumeTlsV1_2Connection() {
-        assumeTrue("TLSv1.2.".equals(negotiatedVersion()));
+        assumeTrue("TLSv1.2".equals(negotiatedVersion()));
     }
 
     /**
diff --git a/openjdk/src/main/java/org/conscrypt/Java8PlatformUtil.java b/openjdk/src/main/java/org/conscrypt/Java8PlatformUtil.java
index ebb8e67..e5c691e 100644
--- a/openjdk/src/main/java/org/conscrypt/Java8PlatformUtil.java
+++ b/openjdk/src/main/java/org/conscrypt/Java8PlatformUtil.java
@@ -77,7 +77,7 @@
         params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder());
         if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) {
             params.setServerNames(Collections.singletonList(
-                    (SNIServerName) new SNIHostName((engine.getHostname()))));
+                    (SNIServerName) new SNIHostName(engine.getHostname())));
         }
     }
 
diff --git a/openjdk/src/main/java/org/conscrypt/Platform.java b/openjdk/src/main/java/org/conscrypt/Platform.java
index 4837fab..9b09074 100644
--- a/openjdk/src/main/java/org/conscrypt/Platform.java
+++ b/openjdk/src/main/java/org/conscrypt/Platform.java
@@ -317,15 +317,6 @@
     static void logEvent(@SuppressWarnings("unused") String message) {}
 
     /**
-     * Returns true if the supplied hostname is an literal IP address.
-     */
-    @SuppressWarnings("unused")
-    static boolean isLiteralIpAddress(String hostname) {
-        // TODO: any RI API to make this better?
-        return AddressUtils.isLiteralIpAddress(hostname);
-    }
-
-    /**
      * For unbundled versions, SNI is always enabled by default.
      */
     @SuppressWarnings("unused")
diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java
index 171d67e..4921cc8 100644
--- a/platform/src/main/java/org/conscrypt/Platform.java
+++ b/platform/src/main/java/org/conscrypt/Platform.java
@@ -272,13 +272,6 @@
         }
     }
 
-    /**
-     * Returns true if the supplied hostname is an literal IP address.
-     */
-    static boolean isLiteralIpAddress(String hostname) {
-        return InetAddress.isNumeric(hostname);
-    }
-
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         return new Java8EngineWrapper(engine);
     }
diff --git a/release/Dockerfile b/release/Dockerfile
index 17072c7..f0d5164 100644
--- a/release/Dockerfile
+++ b/release/Dockerfile
@@ -1,7 +1,4 @@
-FROM centos:6.6
-
-# This enables compatibility with Docker overlayfs
-RUN yum install -y yum-plugin-ovl
+FROM centos:7
 
 RUN yum install -y git \
                    tar \
@@ -18,10 +15,6 @@
                    glibc-devel \
                    glibc-devel.i686
 
-# Install clang.
-RUN yum install -y epel-release
-RUN yum install -y clang
-
 RUN yum update -y nss
 
 # Install Java 8
@@ -32,24 +25,17 @@
 ENV JAVA_HOME /var/local/jdk1.8.0_131
 ENV PATH $JAVA_HOME/bin:$PATH
 
-# Install GCC 4.8
-# We'll get and "Rpmdb checksum is invalid: dCDPT(pkg checksums)" error caused by
-# docker issue when using overlay storage driver, but all the stuff we need
-# will be installed, so for now we just ignore the error.
-WORKDIR /etc/yum.repos.d
-RUN wget --no-check-certificate http://people.centos.org/tru/devtools-2/devtools-2.repo
-RUN yum install -y devtoolset-2-gcc \
-                   devtoolset-2-binutils \
-                   devtoolset-2-gcc-c++ \
-                   || true
-ENV CC /opt/rh/devtoolset-2/root/usr/bin/gcc
-ENV CXX /opt/rh/devtoolset-2/root/usr/bin/g++
+# Install Clang 5
+RUN yum install -y centos-release-scl
+RUN yum install -y llvm-toolset-7
+ENV CC /opt/rh/llvm-toolset-7/root/usr/bin/clang
+ENV CXX /opt/rh/llvm-toolset-7/root/usr/bin/clang++
 
 # Download and install Golang
 WORKDIR /
-ENV GOLANG_VERSION 1.6.4
+ENV GOLANG_VERSION 1.10.5
 ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
-ENV GOLANG_DOWNLOAD_SHA256 b58bf5cede40b21812dfa031258db18fc39746cc0972bc26dae0393acc377aaf
+ENV GOLANG_DOWNLOAD_SHA256 a035d9beda8341b645d3f45a1b620cf2d8fb0c5eb409be36b389c0fd384ecc3a
 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
 	&& echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - \
 	&& tar -C /usr/local -xzf golang.tar.gz \
@@ -77,7 +63,7 @@
 
 # Build and install Python from source.
 WORKDIR /usr/src
-ENV PYTHON_VERSION 2.7.10
+ENV PYTHON_VERSION 2.7.14
 RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz && \
   tar xvzf Python-${PYTHON_VERSION}.tgz && \
   cd Python-${PYTHON_VERSION} && \
@@ -88,7 +74,7 @@
 
 # Build and install ninja from source.
 WORKDIR /usr/src
-ENV NINJA_VERSION 1.6.0
+ENV NINJA_VERSION 1.8.2
 RUN git clone https://github.com/martine/ninja.git && \
   cd ninja && \
   git checkout v$NINJA_VERSION && \
@@ -107,7 +93,7 @@
 
 # Download conscrypt.
 WORKDIR /
-RUN git clone --depth 1 https://github.com/google/conscrypt.git
+RUN git clone --depth 1 --no-single-branch https://github.com/google/conscrypt.git
 
-# Start in devtoolset environment that uses GCC 4.8
-CMD ["scl", "enable", "devtoolset-2", "bash"]
+# Start in toolset environment that uses Clang 5
+CMD ["scl", "enable", "llvm-toolset-7", "bash"]
diff --git a/release/README.md b/release/README.md
index 0af1239..0b8eb50 100644
--- a/release/README.md
+++ b/release/README.md
@@ -22,7 +22,7 @@
 <!-- TODO(flooey): Expand and link these, there's probably more -->
 * Linux: [Docker](https://www.docker.com/), [Android SDK](https://developer.android.com/studio/index.html)
 * MacOS: Java SDK
-* Windows: MSVC, git, yasm, Java
+* Windows: MSVC, git, NASM, Java
 
 ### Setup OSSRH and GPG
 
diff --git a/release/linux b/release/linux
index 15ceefa..2dd9f51 100755
--- a/release/linux
+++ b/release/linux
@@ -37,4 +37,4 @@
 docker cp "$(grep signingKeystore ~/.gradle/gradle.properties | cut -d= -f2)" $CONTAINER_ID:/root/certkeystore
 
 # Run the release automation script for the docker container
-docker exec $CONTAINER_ID scl enable devtoolset-2 "/conscrypt/release/docker $1"
+docker exec $CONTAINER_ID scl enable llvm-toolset-7 "/conscrypt/release/docker $1"
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java b/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java
index 02ecdf0..4f7da03 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/AddressUtils.java
@@ -42,10 +42,8 @@
         }
 
         // Must be a FQDN that does not have a trailing dot.
-        return (sniHostname.equalsIgnoreCase("localhost")
-                    || sniHostname.indexOf('.') != -1)
-                && !Platform.isLiteralIpAddress(sniHostname)
-                && !sniHostname.endsWith(".")
+        return (sniHostname.equalsIgnoreCase("localhost") || sniHostname.indexOf('.') != -1)
+                && !isLiteralIpAddress(sniHostname) && !sniHostname.endsWith(".")
                 && sniHostname.indexOf('\0') == -1;
     }
 
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
index 9935dff..a7de6a5 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
@@ -146,7 +146,7 @@
     /**
      * Set during startHandshake.
      */
-    private final ActiveSession activeSession;
+    private ActiveSession activeSession;
 
     /**
      * A snapshot of the active session when the engine was closed.
@@ -185,7 +185,6 @@
         peerInfoProvider = PeerInfoProvider.nullProvider();
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     ConscryptEngine(String host, int port, SSLParametersImpl sslParameters) {
@@ -193,7 +192,6 @@
         this.peerInfoProvider = PeerInfoProvider.forHostAndPort(host, port);
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     ConscryptEngine(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider) {
@@ -201,7 +199,6 @@
         this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider");
         this.ssl = newSsl(sslParameters, this);
         this.networkBio = ssl.newBio();
-        activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
     }
 
     private static NativeSsl newSsl(SSLParametersImpl sslParameters, ConscryptEngine engine) {
@@ -465,10 +462,15 @@
             if (state == STATE_CLOSED || state == STATE_CLOSED_INBOUND) {
                 return;
             }
-            if (isOutboundDone()) {
-                closeAndFreeResources();
+            if (isHandshakeStarted()) {
+                if (isOutboundDone()) {
+                    closeAndFreeResources();
+                } else {
+                    transitionTo(STATE_CLOSED_INBOUND);
+                }
             } else {
-                transitionTo(STATE_CLOSED_INBOUND);
+                // Never started the handshake. Just close now.
+                closeAndFreeResources();
             }
         }
     }
@@ -1820,10 +1822,11 @@
         switch (newState) {
             case STATE_HANDSHAKE_STARTED: {
                 handshakeFinished = false;
+                activeSession = new ActiveSession(ssl, sslParameters.getSessionContext());
                 break;
             }
             case STATE_CLOSED: {
-                if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED ) {
+                if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED) {
                     closedSession = new SessionSnapshot(activeSession);
                 }
                 break;
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java b/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java
index 46e0be4..fd62130 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/EvpMdRef.java
@@ -33,18 +33,15 @@
      */
     static String getJcaDigestAlgorithmStandardName(String algorithm) {
         String algorithmUpper = algorithm.toUpperCase(Locale.US);
-        if ((SHA256.JCA_NAME.equals(algorithmUpper)) || (SHA256.OID.equals(algorithmUpper))) {
+        if (SHA256.JCA_NAME.equals(algorithmUpper) || SHA256.OID.equals(algorithmUpper)) {
             return SHA256.JCA_NAME;
-        } else if ((SHA512.JCA_NAME.equals(algorithmUpper))
-                || (SHA512.OID.equals(algorithmUpper))) {
+        } else if (SHA512.JCA_NAME.equals(algorithmUpper) || SHA512.OID.equals(algorithmUpper)) {
             return SHA512.JCA_NAME;
-        } else if ((SHA1.JCA_NAME.equals(algorithmUpper)) || (SHA1.OID.equals(algorithmUpper))) {
+        } else if (SHA1.JCA_NAME.equals(algorithmUpper) || SHA1.OID.equals(algorithmUpper)) {
             return SHA1.JCA_NAME;
-        } else if ((SHA384.JCA_NAME.equals(algorithmUpper))
-                || (SHA384.OID.equals(algorithmUpper))) {
+        } else if (SHA384.JCA_NAME.equals(algorithmUpper) || SHA384.OID.equals(algorithmUpper)) {
             return SHA384.JCA_NAME;
-        } else if ((SHA224.JCA_NAME.equals(algorithmUpper))
-                || (SHA224.OID.equals(algorithmUpper))) {
+        } else if (SHA224.JCA_NAME.equals(algorithmUpper) || SHA224.OID.equals(algorithmUpper)) {
             return SHA224.JCA_NAME;
         } else {
             return null;
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
index c7f9659..585eee2 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeSsl.java
@@ -435,7 +435,7 @@
         if (pskKeyManager != null) {
             boolean pskEnabled = false;
             for (String enabledCipherSuite : parameters.enabledCipherSuites) {
-                if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
+                if ((enabledCipherSuite != null) && enabledCipherSuite.contains("PSK")) {
                     pskEnabled = true;
                     break;
                 }
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java
index 9574de4..6a14d01 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLBIOInputStream.java
@@ -77,4 +77,35 @@
 
         return offset;
     }
+
+    @Override
+    public int read(byte[] buffer) throws IOException {
+        return read(buffer, 0, buffer.length);
+    }
+
+    // InputStream.read() is allowed to return less than len bytes, and the socket InputStreams
+    // that are used with this class typically do so when the length requested is more than what
+    // is already buffered, but some users of BoringSSL's BIO APIs expect that any read call either
+    // fills the buffer completely, fails, or reaches EOF.  We patch over this difference by
+    // repeatedly calling super.read() until it indicates EOF or we fill the buffer.
+    @Override
+    public int read(byte[] buffer, int offset, int len) throws IOException {
+        if (offset < 0 || len < 0 || len > buffer.length - offset) {
+            throw new IndexOutOfBoundsException("Invalid bounds");
+        }
+        if (len == 0) {
+            return 0;
+        }
+        int totalRead = 0;
+        int read;
+        do {
+            read = super.read(buffer, offset + totalRead, len - totalRead - offset);
+            if (read == -1) {
+                break;
+            }
+            totalRead += read;
+        } while (offset + totalRead < len);
+
+        return totalRead == 0 ? -1 : totalRead;
+    }
 }
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
index 766da4d..78012a6 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLECKeyFactory.java
@@ -181,7 +181,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
+        } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
@@ -191,7 +191,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
+        } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
index 37f68db..0d5ea12 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAKeyFactory.java
@@ -232,7 +232,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
+        } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
@@ -242,7 +242,7 @@
             } catch (InvalidKeySpecException e) {
                 throw new InvalidKeyException(e);
             }
-        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
+        } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
             byte[] encoded = key.getEncoded();
             if (encoded == null) {
                 throw new InvalidKeyException("Key does not support encoding");
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java
index 61efe44..88a9816 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPublicKey.java
@@ -101,7 +101,7 @@
         return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
     }
 
-    private void ensureReadParams() {
+    private synchronized void ensureReadParams() {
         if (fetchedParams) {
             return;
         }
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
index d808c0d..a34bc62 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLSignature.java
@@ -449,8 +449,8 @@
             }
 
             String specMgfAlgorithm = spec.getMGFAlgorithm();
-            if ((!EvpMdRef.MGF1_ALGORITHM_NAME.equalsIgnoreCase(specMgfAlgorithm))
-                    && (!EvpMdRef.MGF1_OID.equals(specMgfAlgorithm))) {
+            if (!EvpMdRef.MGF1_ALGORITHM_NAME.equalsIgnoreCase(specMgfAlgorithm)
+                    && !EvpMdRef.MGF1_OID.equals(specMgfAlgorithm)) {
                 throw new InvalidAlgorithmParameterException(
                         "Unsupported MGF algorithm: " + specMgfAlgorithm + ". Only "
                                 + EvpMdRef.MGF1_ALGORITHM_NAME + " supported");
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
index 4210c92..62b95cc 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/KeyPairGeneratorTest.java
@@ -328,7 +328,7 @@
                 continue;
             }
             if ("EC".equals(algorithm)
-                    && ("SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName()))
+                    && "SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())
                     && keySize == 224) {
                 // TODO(flooey): Remove when we stop supporting Java 6
                 // This Sun provider doesn't support 224-bit EC keys
@@ -347,8 +347,7 @@
             test_KeyPair(kpg, kpg.generateKeyPair());
         }
 
-        if (("EC".equals(algorithm)) || ("ECDH".equals(algorithm))
-                || ("ECDSA".equals(algorithm))) {
+        if ("EC".equals(algorithm) || "ECDH".equals(algorithm) || "ECDSA".equals(algorithm)) {
             if ("SunPKCS11-NSS".equalsIgnoreCase(kpg.getProvider().getName())) {
                 // SunPKCS11 doesn't support some of the named curves that we expect, so it
                 // fails.  Skip it.
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
index e7fdecb..0c43cd0 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/SignatureTest.java
@@ -173,8 +173,8 @@
             kpAlgorithm = "EC";
         } else if (sigAlgorithmUpperCase.endsWith("DSA")) {
             kpAlgorithm = "DSA";
-        } else if ((sigAlgorithmUpperCase.endsWith("RSA"))
-                || (sigAlgorithmUpperCase.endsWith("RSA/PSS"))) {
+        } else if (sigAlgorithmUpperCase.endsWith("RSA")
+                || sigAlgorithmUpperCase.endsWith("RSA/PSS")) {
             kpAlgorithm = "RSA";
         } else {
             throw new Exception("Unknown KeyPair algorithm for Signature algorithm "
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
index 5f60849..7c2128f 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/java/security/cert/CertificateFactoryTest.java
@@ -26,6 +26,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
@@ -62,6 +63,7 @@
 import org.bouncycastle.x509.X509V3CertificateGenerator;
 import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
 import com.android.org.conscrypt.Conscrypt;
+import com.android.org.conscrypt.TestUtils;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -198,6 +200,23 @@
             + "AAAAAAAA\n"
             + "-----END CERTIFICATE-----";
 
+    private static final String VALID_CERTIFICATE_DER_BASE64 =
+            "MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQG"
+            + "EwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhh"
+            + "d3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0xMTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVT"
+            + "MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApH"
+            + "b29nbGUgSW5jMRcwFQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw"
+            + "gYkCgYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jNgtXj9xVo"
+            + "RaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L05vuuWciKh0R73mkszeK"
+            + "9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAMBgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0w"
+            + "K6ApoCeGJWh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYI"
+            + "KwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzAB"
+            + "hhZodHRwOi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0ZS5j"
+            + "b20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUFAAOBgQCfQ89bxFAp"
+            + "sb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5u2ONgJd8IyAPkU0Wueru9G2Jysa9"
+            + "zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqA"
+            + "ibAxWEEHXw==";
+
     @Test
     public void test_generateCertificate() throws Exception {
         Provider[] providers = Security.getProviders("CertificateFactory.X509");
@@ -209,6 +228,7 @@
                 test_generateCertificate_InputStream_Empty(cf);
                 test_generateCertificate_InputStream_InvalidStart_Failure(cf);
                 test_generateCertificate_AnyLineLength_Success(cf);
+                test_generateCertificate_PartialInput(cf);
             } catch (Throwable e) {
                 throw new Exception("Problem testing " + p.getName(), e);
             }
@@ -228,6 +248,12 @@
             assertNotNull(c);
         }
 
+        {
+            byte[] valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+            Certificate c = cf.generateCertificate(new ByteArrayInputStream(valid));
+            assertNotNull(c);
+        }
+
         try {
             byte[] invalid = INVALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
             cf.generateCertificate(new ByteArrayInputStream(invalid));
@@ -413,6 +439,44 @@
         }
     }
 
+    /**
+     * An InputStream that only returns two bytes at a time, no matter how many were requested.
+     */
+    private static class SlowInputStream extends FilterInputStream {
+        protected SlowInputStream(InputStream inputStream) {
+            super(inputStream);
+        }
+
+        @Override
+        public int read(byte[] buffer) throws IOException {
+            if (buffer.length < 2) {
+                return super.read(buffer);
+            }
+            return super.read(buffer, 0, 2);
+        }
+
+        @Override
+        public int read(byte[] buffer, int offset, int len) throws IOException {
+            if (len < 2) {
+                return super.read(buffer, offset, len);
+            }
+            return super.read(buffer, offset, 2);
+        }
+    }
+
+    // Test that certificates are decoded properly even if the InputStream is unhelpful and only
+    // returns partial inputs on basically every request.
+    private void test_generateCertificate_PartialInput(CertificateFactory cf) throws Exception {
+        byte[] valid = VALID_CERTIFICATE_PEM.getBytes(Charset.defaultCharset());
+        Certificate c =
+                cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+        assertNotNull(c);
+
+        valid = TestUtils.decodeBase64(VALID_CERTIFICATE_DER_BASE64);
+        c = cf.generateCertificate(new SlowInputStream(new ByteArrayInputStream(valid)));
+        assertNotNull(c);
+    }
+
     /* CertPath tests */
     @Test
     public void testGenerateCertPath() throws Exception {
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
index 2dbd5a5..6641504 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/crypto/CipherTest.java
@@ -114,13 +114,13 @@
     /** GCM tag size used for tests. */
     private static final int GCM_TAG_SIZE_BITS = 96;
 
-    private static final String[] RSA_PROVIDERS = ((StandardNames.IS_RI)
-        ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
-        : new String[] { "BC" , StandardNames.JSSE_PROVIDER_NAME });
+    private static final String[] RSA_PROVIDERS = StandardNames.IS_RI
+            ? new String[] {"SunJCE", StandardNames.JSSE_PROVIDER_NAME}
+            : new String[] {"BC", StandardNames.JSSE_PROVIDER_NAME};
 
-    private static final String[] AES_PROVIDERS = ((StandardNames.IS_RI)
-        ? new String[] { "SunJCE", StandardNames.JSSE_PROVIDER_NAME }
-        : new String[] { "BC", StandardNames.JSSE_PROVIDER_NAME });
+    private static final String[] AES_PROVIDERS = StandardNames.IS_RI
+            ? new String[] {"SunJCE", StandardNames.JSSE_PROVIDER_NAME}
+            : new String[] {"BC", StandardNames.JSSE_PROVIDER_NAME};
 
     private static boolean isSupported(String algorithm, String provider) {
         if (algorithm.equals("RC2")) {
@@ -1391,11 +1391,9 @@
 
         if (expectedOaepSpec.getPSource() instanceof PSource.PSpecified
                 && actualOaepSpec.getPSource() instanceof PSource.PSpecified) {
-            assertEquals(
-                    Arrays.toString(
-                            ((PSource.PSpecified) expectedOaepSpec.getPSource()).getValue()),
-                    Arrays.toString(
-                            (((PSource.PSpecified) actualOaepSpec.getPSource()).getValue())));
+            assertEquals(Arrays.toString(
+                                 ((PSource.PSpecified) expectedOaepSpec.getPSource()).getValue()),
+                    Arrays.toString(((PSource.PSpecified) actualOaepSpec.getPSource()).getValue()));
         } else {
             fail("Unknown PSource type");
         }
@@ -4593,14 +4591,13 @@
             if (c.contains("/CBC/")) {
                 cipher.init(Cipher.DECRYPT_MODE,
                         new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
-                                (c.startsWith("AES/")) ? "AES" : "DESEDE"),
-                        new IvParameterSpec(
-                                ("01234567" + ((c.startsWith("AES/")) ? "89012345" : ""))
-                                        .getBytes(StandardCharsets.US_ASCII)));
+                                c.startsWith("AES/") ? "AES" : "DESEDE"),
+                        new IvParameterSpec(("01234567" + (c.startsWith("AES/") ? "89012345" : ""))
+                                                    .getBytes(StandardCharsets.US_ASCII)));
             } else {
                 cipher.init(Cipher.DECRYPT_MODE,
                         new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII),
-                                (c.startsWith("AES/")) ? "AES" : "DESEDE"));
+                                c.startsWith("AES/") ? "AES" : "DESEDE"));
             }
 
             byte[] buffer = new byte[0];
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
index 28158cc..6b49d0f 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyManagerFactoryTest.java
@@ -24,7 +24,7 @@
 import static org.junit.Assert.fail;
 
 import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore.Builder;
+import java.security.KeyStore;
 import java.security.KeyStore.PasswordProtection;
 import java.security.KeyStore.PrivateKeyEntry;
 import java.security.PrivateKey;
@@ -123,7 +123,7 @@
 
         // init with KeyStoreBuilderParameters ManagerFactoryParameters
         PasswordProtection pp = new PasswordProtection(getTestKeyStore().storePassword);
-        Builder builder = Builder.newInstance(getTestKeyStore().keyStore, pp);
+        KeyStore.Builder builder = KeyStore.Builder.newInstance(getTestKeyStore().keyStore, pp);
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
         if (supportsManagerFactoryParameters(kmf.getAlgorithm())) {
             kmf.init(ksbp);
@@ -199,8 +199,11 @@
             }
         }
 
-        String a = km.chooseClientAlias(keyTypes, null, null);
-        test_X509KeyManager_alias(km, a, null, true, empty);
+        String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+        for (String[] keyList : rotatedTypes) {
+            String alias = km.chooseClientAlias(keyList, null, null);
+            test_X509KeyManager_alias(km, alias, null, true, empty);
+        }
 
         for (String keyType : keyTypes) {
             String[] array = new String[] {keyType};
@@ -219,8 +222,12 @@
     private void test_X509ExtendedKeyManager(
             X509ExtendedKeyManager km, boolean empty, String algorithm) throws Exception {
         String[] keyTypes = keyTypes(algorithm);
-        String a = km.chooseEngineClientAlias(keyTypes, null, null);
-        test_X509KeyManager_alias(km, a, null, true, empty);
+        String[][] rotatedTypes = rotate(nonEmpty(keyTypes));
+        for (String[] keyList : rotatedTypes) {
+            String alias = km.chooseEngineClientAlias(keyList, null, null);
+            test_X509KeyManager_alias(km, alias, null, true, empty);
+        }
+
         for (String keyType : keyTypes) {
             String[] array = new String[] {keyType};
             String alias = km.chooseEngineClientAlias(array, null, null);
@@ -232,6 +239,30 @@
         }
     }
 
+    // Filters null or empty values from a String array and returns a new array with the results.
+    private static String[] nonEmpty(String[] input) {
+        String[] nonEmpty = new String[input.length];
+        int size = 0;
+        for (String keyType : input) {
+            if (keyType != null && !keyType.isEmpty()) {
+                nonEmpty[size++] = keyType;
+            }
+        }
+        return Arrays.copyOfRange(nonEmpty, 0, size);
+    }
+
+    // Generates an array of arrays of all the rotational permutations of its input.
+    private static String[][] rotate(String[] input) {
+        int size = input.length;
+        String[][] result = new String[size][size];
+        for (int i = 0; i < size; i++) {
+            for (int j = 0; j < size; j++) {
+                result[i][j] = input[(i + j) % size];
+            }
+        }
+        return result;
+    }
+
     private void test_X509KeyManager_alias(X509KeyManager km, String alias, String keyType,
             boolean many, boolean empty) throws Exception {
         if (empty || (!many && (keyType == null || keyType.isEmpty()))) {
@@ -240,8 +271,7 @@
             assertNull(keyType, km.getPrivateKey(alias));
             return;
         }
-        assertNotNull(keyType, alias);
-
+        assertNotNull(alias);
         X509Certificate[] certificateChain = km.getCertificateChain(alias);
         PrivateKey privateKey = km.getPrivateKey(alias);
 
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
index ab5a6c8..ff34e5b 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/KeyStoreBuilderParametersTest.java
@@ -23,7 +23,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
-import java.security.KeyStore.Builder;
+import java.security.KeyStore;
 import java.security.KeyStore.PasswordProtection;
 import java.util.Arrays;
 import java.util.List;
@@ -57,7 +57,7 @@
         // Objects.requireNonNull was added
         assumeObjectsAvailable();
         try {
-            new KeyStoreBuilderParameters((Builder) null);
+            new KeyStoreBuilderParameters((KeyStore.Builder) null);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -66,7 +66,7 @@
     @Test
     public void test_init_Builder() {
         TestKeyStore testKeyStore = TestKeyStore.getClient();
-        Builder builder = Builder.newInstance(
+        KeyStore.Builder builder = KeyStore.Builder.newInstance(
                 testKeyStore.keyStore, new PasswordProtection(testKeyStore.storePassword));
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
         assertNotNull(ksbp);
@@ -78,7 +78,7 @@
     @Test
     public void test_init_List_null() {
         try {
-            new KeyStoreBuilderParameters((List<Builder>) null);
+            new KeyStoreBuilderParameters((List<KeyStore.Builder>) null);
             fail();
         } catch (NullPointerException expected) {
             // Ignored.
@@ -89,12 +89,12 @@
     public void test_init_List() {
         TestKeyStore testKeyStore1 = TestKeyStore.getClient();
         TestKeyStore testKeyStore2 = TestKeyStore.getServer();
-        Builder builder1 = Builder.newInstance(
+        KeyStore.Builder builder1 = KeyStore.Builder.newInstance(
                 testKeyStore1.keyStore, new PasswordProtection(testKeyStore1.storePassword));
-        Builder builder2 = Builder.newInstance(
+        KeyStore.Builder builder2 = KeyStore.Builder.newInstance(
                 testKeyStore2.keyStore, new PasswordProtection(testKeyStore2.storePassword));
 
-        List<Builder> list = Arrays.asList(builder1, builder2);
+        List<KeyStore.Builder> list = Arrays.asList(builder1, builder2);
         KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(list);
         assertNotNull(ksbp);
         assertNotNull(ksbp.getParameters());
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
index dcbbd11..2830308 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLContextTest.java
@@ -177,11 +177,10 @@
             SSLContext context = SSLContext.getInstance(tlsVersion);
             context.init(null, null, null);
 
-            StandardNames.assertSSLContextEnabledProtocols(
-                    tlsVersion, ((SSLSocket) (context.getSocketFactory().createSocket()))
-                                        .getEnabledProtocols());
             StandardNames.assertSSLContextEnabledProtocols(tlsVersion,
-                    ((SSLServerSocket) (context.getServerSocketFactory().createServerSocket()))
+                    ((SSLSocket) context.getSocketFactory().createSocket()).getEnabledProtocols());
+            StandardNames.assertSSLContextEnabledProtocols(tlsVersion,
+                    ((SSLServerSocket) context.getServerSocketFactory().createServerSocket())
                             .getEnabledProtocols());
             StandardNames.assertSSLContextEnabledProtocols(
                     tlsVersion, context.getDefaultSSLParameters().getProtocols());
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
index f9ac005..643d95b 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineTest.java
@@ -252,8 +252,8 @@
                 boolean serverAuthenticatedUsingPublicKey = true;
                 if (cipherSuite.contains("_anon_")) {
                     serverAuthenticatedUsingPublicKey = false;
-                } else if ((cipherSuite.startsWith("TLS_PSK_"))
-                        || (cipherSuite.startsWith("TLS_ECDHE_PSK_"))) {
+                } else if (cipherSuite.startsWith("TLS_PSK_")
+                        || cipherSuite.startsWith("TLS_ECDHE_PSK_")) {
                     serverAuthenticatedUsingPublicKey = false;
                 }
                 if (serverAuthenticatedUsingPublicKey) {
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
index 3b09e7c..df8e1ee 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLEngineVersionCompatibilityTest.java
@@ -666,9 +666,9 @@
                 && !b.isInboundDone() && !a.isOutboundDone() && !b.isOutboundDone());
     }
 
-    // Assumes that the negotiated connection will be
+    // Assumes that the negotiated connection will be TLS 1.2
     private void assumeTlsV1_2Connection() {
-        assumeTrue("TLSv1.2.".equals(negotiatedVersion()));
+        assumeTrue("TLSv1.2".equals(negotiatedVersion()));
     }
 
     /**
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
index fd70c4d..8fe6bb5 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSessionContextTest.java
@@ -333,7 +333,7 @@
     }
 
     private int expectedSslSessionCacheTimeout(TestSSLContext c) {
-        return (isConscrypt(c.serverContext.getProvider())) ? 8 * 3600 : 24 * 3600;
+        return isConscrypt(c.serverContext.getProvider()) ? 8 * 3600 : 24 * 3600;
     }
 
     private static int numSessions(SSLSessionContext s) {
diff --git a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
index 7eb14cb..4f988bf 100644
--- a/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
+++ b/repackaged/openjdk-integ-tests/src/test/java/com/android/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -1598,8 +1598,8 @@
         server.getOutputStream().write(42);
         assertEquals(42, handshakeFuture.get().intValue());
 
-        final Socket toRead = (readUnderlying) ? underlying : clientWrapping;
-        final Socket toClose = (closeUnderlying) ? underlying : clientWrapping;
+        final Socket toRead = readUnderlying ? underlying : clientWrapping;
+        final Socket toClose = closeUnderlying ? underlying : clientWrapping;
 
         // Schedule the socket to be closed in 1 second.
         Future<Void> future = runAsync(new Callable<Void>() {
@@ -2118,6 +2118,12 @@
                     || cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)) {
                 continue;
             }
+            /*
+             * tls_unique only works on 1.2, so skip TLS 1.3 cipher suites.
+             */
+            if (StandardNames.CIPHER_SUITES_TLS13.contains(cipherSuite)) {
+                continue;
+            }
             TestSSLSocketPair pair = TestSSLSocketPair.create(c);
             try {
                 String[] cipherSuites =
@@ -2294,9 +2300,9 @@
         }
     }
 
-    // Assumes that the negotiated connection will be
+    // Assumes that the negotiated connection will be TLS 1.2
     private void assumeTlsV1_2Connection() {
-        assumeTrue("TLSv1.2.".equals(negotiatedVersion()));
+        assumeTrue("TLSv1.2".equals(negotiatedVersion()));
     }
 
     /**
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java
index ade0ef2..d07516f 100644
--- a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Java8PlatformUtil.java
@@ -78,7 +78,7 @@
         params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder());
         if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) {
             params.setServerNames(Collections.singletonList(
-                    (SNIServerName) new SNIHostName((engine.getHostname()))));
+                    (SNIServerName) new SNIHostName(engine.getHostname())));
         }
     }
 
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
index 3ed2803..ff484b0 100644
--- a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
@@ -318,15 +318,6 @@
     static void logEvent(@SuppressWarnings("unused") String message) {}
 
     /**
-     * Returns true if the supplied hostname is an literal IP address.
-     */
-    @SuppressWarnings("unused")
-    static boolean isLiteralIpAddress(String hostname) {
-        // TODO: any RI API to make this better?
-        return AddressUtils.isLiteralIpAddress(hostname);
-    }
-
-    /**
      * For unbundled versions, SNI is always enabled by default.
      */
     @SuppressWarnings("unused")
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
index 3a27d91..79d046b 100644
--- a/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
@@ -273,13 +273,6 @@
         }
     }
 
-    /**
-     * Returns true if the supplied hostname is an literal IP address.
-     */
-    static boolean isLiteralIpAddress(String hostname) {
-        return InetAddress.isNumeric(hostname);
-    }
-
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         return new Java8EngineWrapper(engine);
     }
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
index 5a47b2d..d4275c6 100644
--- a/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
@@ -71,7 +71,7 @@
         String methodName = method.getName();
         Class<?>[] parameterTypes = method.getParameterTypes();
         boolean sslEngineVariant = (parameterTypes.length > 0)
-                && (SSLEngine.class.equals(parameterTypes[parameterTypes.length - 1]));
+                && SSLEngine.class.equals(parameterTypes[parameterTypes.length - 1]);
         if ("getKey".equals(methodName)) {
             if (sslEngineVariant) {
                 return getKey((String) args[0], (String) args[1], (SSLEngine) args[2]);
diff --git a/test_logging.properties b/test_logging.properties
index 1204c2d..fc76518 100644
--- a/test_logging.properties
+++ b/test_logging.properties
@@ -9,3 +9,4 @@
 
 # Avoid nuisance logs in tests.
 org.conscrypt.NativeSslSession.level=SEVERE
+org.conscrypt.TrustManagerImpl.level=INFO
diff --git a/testing/src/main/java/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java b/testing/src/main/java/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
index 64f57fb..61bf43a 100644
--- a/testing/src/main/java/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
+++ b/testing/src/main/java/org/conscrypt/javax/net/ssl/PSKKeyManagerProxy.java
@@ -70,7 +70,7 @@
         String methodName = method.getName();
         Class<?>[] parameterTypes = method.getParameterTypes();
         boolean sslEngineVariant = (parameterTypes.length > 0)
-                && (SSLEngine.class.equals(parameterTypes[parameterTypes.length - 1]));
+                && SSLEngine.class.equals(parameterTypes[parameterTypes.length - 1]);
         if ("getKey".equals(methodName)) {
             if (sslEngineVariant) {
                 return getKey((String) args[0], (String) args[1], (SSLEngine) args[2]);