Merge "Put back sdk_version: "current""
diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
index 8b90a72..d10ff20 100644
--- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
@@ -34,6 +34,7 @@
 
 #include <openssl/aead.h>
 #include <openssl/asn1.h>
+#include <openssl/chacha.h>
 #include <openssl/engine.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
@@ -1545,6 +1546,40 @@
     return joa;
 }
 
+static void NativeCrypto_chacha20_encrypt_decrypt(JNIEnv* env, jclass, jbyteArray inBytes,
+        jint inOffset, jbyteArray outBytes, jint outOffset, jint length, jbyteArray keyBytes,
+        jbyteArray nonceBytes, jint blockCounter) {
+    JNI_TRACE("chacha20_encrypt_decrypt");
+    ScopedByteArrayRO in(env, inBytes);
+    if (in.get() == nullptr) {
+        JNI_TRACE("chacha20_encrypt_decrypt => threw exception: could not read input bytes");
+        return;
+    }
+    ScopedByteArrayRW out(env, outBytes);
+    if (out.get() == nullptr) {
+        JNI_TRACE("chacha20_encrypt_decrypt => threw exception: could not read output bytes");
+        return;
+    }
+    ScopedByteArrayRO key(env, keyBytes);
+    if (key.get() == nullptr) {
+        JNI_TRACE("chacha20_encrypt_decrypt => threw exception: could not read key bytes");
+        return;
+    }
+    ScopedByteArrayRO nonce(env, nonceBytes);
+    if (nonce.get() == nullptr) {
+        JNI_TRACE("chacha20_encrypt_decrypt => threw exception: could not read nonce bytes");
+        return;
+    }
+
+    CRYPTO_chacha_20(
+            reinterpret_cast<unsigned char*>(out.get()) + outOffset,
+            reinterpret_cast<const unsigned char*>(in.get()) + inOffset,
+            length,
+            reinterpret_cast<const unsigned char*>(key.get()),
+            reinterpret_cast<const unsigned char*>(nonce.get()),
+            blockCounter);
+}
+
 static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava) {
     JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava);
 
@@ -9355,6 +9390,7 @@
         CONSCRYPT_NATIVE_METHOD(RSA_private_decrypt, "(I[B[B" REF_EVP_PKEY "I)I"),
         CONSCRYPT_NATIVE_METHOD(get_RSA_private_params, "(" REF_EVP_PKEY ")[[B"),
         CONSCRYPT_NATIVE_METHOD(get_RSA_public_params, "(" REF_EVP_PKEY ")[[B"),
+        CONSCRYPT_NATIVE_METHOD(chacha20_encrypt_decrypt, "([BI[BII[B[BI)V"),
         CONSCRYPT_NATIVE_METHOD(EC_GROUP_new_by_curve_name, "(Ljava/lang/String;)J"),
         CONSCRYPT_NATIVE_METHOD(EC_GROUP_new_arbitrary, "([B[B[B[B[B[BI)J"),
         CONSCRYPT_NATIVE_METHOD(EC_GROUP_get_curve_name, "(" REF_EC_GROUP ")Ljava/lang/String;"),
diff --git a/common/src/main/java/org/conscrypt/KeyManagerImpl.java b/common/src/main/java/org/conscrypt/KeyManagerImpl.java
index 27c0f60..8975446 100644
--- a/common/src/main/java/org/conscrypt/KeyManagerImpl.java
+++ b/common/src/main/java/org/conscrypt/KeyManagerImpl.java
@@ -29,9 +29,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.X509ExtendedKeyManager;
 import javax.security.auth.x500.X500Principal;
@@ -49,16 +50,13 @@
 class KeyManagerImpl extends X509ExtendedKeyManager {
 
     // hashed key store information
-    private final Hashtable<String, PrivateKeyEntry> hash;
+    private final HashMap<String, PrivateKeyEntry> hash;
 
     /**
      * Creates Key manager
-     *
-     * @param keyStore
-     * @param pwd
      */
     KeyManagerImpl(KeyStore keyStore, char[] pwd) {
-        this.hash = new Hashtable<String, PrivateKeyEntry>();
+        this.hash = new HashMap<String, PrivateKeyEntry>();
         final Enumeration<String> aliases;
         try {
             aliases = keyStore.aliases();
@@ -73,12 +71,12 @@
                             .getEntry(alias, new KeyStore.PasswordProtection(pwd));
                     hash.put(alias, entry);
                 }
-            } catch (KeyStoreException e) {
-                continue;
-            } catch (UnrecoverableEntryException e) {
-                continue;
-            } catch (NoSuchAlgorithmException e) {
-                continue;
+            } catch (KeyStoreException ignored) {
+                // Ignored.
+            } catch (UnrecoverableEntryException ignored) {
+                // Ignored.
+            } catch (NoSuchAlgorithmException ignored) {
+                // Ignored.
             }
         }
     }
@@ -153,10 +151,9 @@
         }
         List<Principal> issuersList = (issuers == null) ? null : Arrays.asList(issuers);
         ArrayList<String> found = new ArrayList<String>();
-        for (Enumeration<String> aliases = hash.keys(); aliases.hasMoreElements();) {
-            final String alias = aliases.nextElement();
-            final KeyStore.PrivateKeyEntry entry = hash.get(alias);
-            final Certificate[] chain = entry.getCertificateChain();
+        for (final Map.Entry<String, PrivateKeyEntry> entry : hash.entrySet()) {
+            final String alias = entry.getKey();
+            final Certificate[] chain = entry.getValue().getCertificateChain();
             final Certificate cert = chain[0];
             final String certKeyAlg = cert.getPublicKey().getAlgorithm();
             final String certSigAlg = (cert instanceof X509Certificate
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index bba13d6..e259907 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -132,6 +132,14 @@
      */
     static native byte[][] get_RSA_private_params(NativeRef.EVP_PKEY rsa);
 
+    // --- ChaCha20 -----------------------
+
+    /**
+     * Returns the encrypted or decrypted version of the data.
+     */
+    static native void chacha20_encrypt_decrypt(byte[] in, int inOffset, byte[] out, int outOffset,
+            int length, byte[] key, byte[] nonce, int blockCounter);
+
     // --- EC functions --------------------------
 
     static native long EVP_PKEY_new_EC_KEY(
diff --git a/common/src/main/java/org/conscrypt/OpenSSLCipher.java b/common/src/main/java/org/conscrypt/OpenSSLCipher.java
index fe7c654..7dc5112 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLCipher.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLCipher.java
@@ -56,6 +56,7 @@
      * Modes that a block cipher may support.
      */
     enum Mode {
+        NONE,
         CBC,
         CTR,
         ECB,
@@ -958,12 +959,16 @@
 
             @Override
             void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
-                throw new NoSuchAlgorithmException("ARC4 does not support modes");
+                if (mode != Mode.NONE && mode != Mode.ECB) {
+                    throw new NoSuchAlgorithmException("Unsupported mode " + mode.toString());
+                }
             }
 
             @Override
             void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
-                throw new NoSuchPaddingException("ARC4 does not support padding");
+                if (padding != Padding.NOPADDING) {
+                    throw new NoSuchPaddingException("Unsupported padding " + padding.toString());
+                }
             }
 
             @Override
@@ -1331,6 +1336,7 @@
                     }
                 }
 
+                @Override
                 protected AlgorithmParameterSpec getParameterSpec(AlgorithmParameters params)
                         throws InvalidAlgorithmParameterException {
                     if (params != null) {
diff --git a/common/src/main/java/org/conscrypt/OpenSSLCipherChaCha20.java b/common/src/main/java/org/conscrypt/OpenSSLCipherChaCha20.java
new file mode 100644
index 0000000..9689ed4
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/OpenSSLCipherChaCha20.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Implementation of the ChaCha20 stream cipher.
+ *
+ * @hide
+ */
+@Internal
+public class OpenSSLCipherChaCha20 extends OpenSSLCipher {
+
+    private static final int BLOCK_SIZE_BYTES = 64;
+    private static final int NONCE_SIZE_BYTES = 12;
+
+    // BoringSSL's interface encrypts by the block, so we need to keep track of whether we
+    // had unused keystream bytes at the end of the previous encryption operation, so that
+    // we can use them before moving on to the next block.
+    private int currentBlockConsumedBytes = 0;
+    private int blockCounter = 0;
+
+    public OpenSSLCipherChaCha20() {}
+
+    @Override
+    void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (params instanceof IvParameterSpec) {
+            IvParameterSpec ivParams = (IvParameterSpec) params;
+            if (ivParams.getIV().length != NONCE_SIZE_BYTES) {
+                throw new InvalidAlgorithmParameterException("IV must be 12 bytes long");
+            }
+            iv = ivParams.getIV();
+        } else {
+            if (!isEncrypting()) {
+                throw new InvalidAlgorithmParameterException(
+                        "IV must be specified when encrypting");
+            }
+            iv = new byte[NONCE_SIZE_BYTES];
+            if (random != null) {
+                random.nextBytes(iv);
+            } else {
+                NativeCrypto.RAND_bytes(iv);
+            }
+        }
+    }
+
+    @Override
+    int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset,
+            int maximumLen) throws ShortBufferException {
+        int inputLenRemaining = inputLen;
+        if (currentBlockConsumedBytes > 0) {
+            // A previous operation ended with a partial block, so we need to encrypt using
+            // the remainder of that block before beginning to use the next block
+            int len = Math.min(BLOCK_SIZE_BYTES - currentBlockConsumedBytes, inputLenRemaining);
+            byte[] singleBlock = new byte[BLOCK_SIZE_BYTES];
+            byte[] singleBlockOut = new byte[BLOCK_SIZE_BYTES];
+            System.arraycopy(input, inputOffset, singleBlock, currentBlockConsumedBytes, len);
+            NativeCrypto.chacha20_encrypt_decrypt(singleBlock, 0, singleBlockOut, 0,
+                    BLOCK_SIZE_BYTES, encodedKey, iv, blockCounter);
+            System.arraycopy(singleBlockOut, currentBlockConsumedBytes, output, outputOffset, len);
+            currentBlockConsumedBytes += len;
+            if (currentBlockConsumedBytes < BLOCK_SIZE_BYTES) {
+                // We still didn't finish this block, so we're done.
+                return len;
+            }
+            assert currentBlockConsumedBytes == BLOCK_SIZE_BYTES;
+            currentBlockConsumedBytes = 0;
+            inputOffset += len;
+            outputOffset += len;
+            inputLenRemaining -= len;
+            blockCounter++;
+        }
+        NativeCrypto.chacha20_encrypt_decrypt(input, inputOffset, output,
+                outputOffset, inputLenRemaining, encodedKey, iv, blockCounter);
+        currentBlockConsumedBytes = inputLenRemaining % BLOCK_SIZE_BYTES;
+        blockCounter += inputLenRemaining / BLOCK_SIZE_BYTES;
+        return inputLen;
+    }
+
+    @Override
+    int doFinalInternal(byte[] output, int outputOffset, int maximumLen)
+            throws IllegalBlockSizeException, BadPaddingException, ShortBufferException {
+        reset();
+        return 0;
+    }
+
+    private void reset() {
+        blockCounter = 0;
+        currentBlockConsumedBytes = 0;
+    }
+
+    @Override
+    String getBaseCipherName() {
+        return "ChaCha20";
+    }
+
+    @Override
+    void checkSupportedKeySize(int keySize) throws InvalidKeyException {
+        if (keySize != 32) {
+            throw new InvalidKeyException("Unsupported key size: " + keySize
+                    + " bytes (must be 32)");
+        }
+    }
+
+    @Override
+    void checkSupportedMode(Mode mode) throws NoSuchAlgorithmException {
+        if (mode != Mode.NONE) {
+            throw new NoSuchAlgorithmException("Mode must be NONE");
+        }
+    }
+
+    @Override
+    void checkSupportedPadding(Padding padding) throws NoSuchPaddingException {
+        if (padding != Padding.NOPADDING) {
+            throw new NoSuchPaddingException("Must be NoPadding");
+        }
+    }
+
+    @Override
+    int getCipherBlockSize() {
+        return 0;
+    }
+
+    @Override
+    int getOutputSizeForFinal(int inputLen) {
+        return inputLen;
+    }
+
+    @Override
+    int getOutputSizeForUpdate(int inputLen) {
+        return inputLen;
+    }
+
+}
diff --git a/common/src/main/java/org/conscrypt/OpenSSLProvider.java b/common/src/main/java/org/conscrypt/OpenSSLProvider.java
index a1a2cd9..fd723f3 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLProvider.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLProvider.java
@@ -411,6 +411,8 @@
                 "AES_256/GCM/NoPadding", "OpenSSLCipher$EVP_AEAD$AES$GCM$AES_256");
 
         putSymmetricCipherImplClass("ChaCha20",
+                "OpenSSLCipherChaCha20");
+        putSymmetricCipherImplClass("ChaCha20/Poly1305/NoPadding",
                 "OpenSSLCipher$EVP_AEAD$ChaCha20");
 
         /* === Mac === */
diff --git a/common/src/main/java/org/conscrypt/SSLUtils.java b/common/src/main/java/org/conscrypt/SSLUtils.java
index ae525ae..09ce91e 100644
--- a/common/src/main/java/org/conscrypt/SSLUtils.java
+++ b/common/src/main/java/org/conscrypt/SSLUtils.java
@@ -345,7 +345,9 @@
     /**
      * Decodes the given list of protocols into {@link String}s.
      * @param protocols the encoded protocol list
-     * @return the decoded protocols or {@code null} if {@code protocols} is {@code null}.
+     * @return the decoded protocols or {@link EmptyArray#BYTE} if {@code protocols} is
+     * empty.
+     * @throws NullPointerException if protocols is {@code null}.
      */
     static String[] decodeProtocols(byte[] protocols) {
         if (protocols.length == 0) {
@@ -382,6 +384,8 @@
      *
      * @param protocols the list of protocols to be encoded
      * @return the encoded form of the protocol list.
+     * @throws IllegalArgumentException if protocols is {@code null}, or if any element is
+     * {@code null} or an empty string.
      */
     static byte[] encodeProtocols(String[] protocols) {
         if (protocols == null) {
diff --git a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
index 8d0427f..86b4533 100644
--- a/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
+++ b/openjdk-integ-tests/src/test/java/libcore/javax/net/ssl/SSLSessionContextTest.java
@@ -24,12 +24,13 @@
 import static org.junit.Assert.fail;
 
 import java.security.Provider;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.Enumeration;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import javax.net.ssl.SSLSessionContext;
 import javax.net.ssl.SSLSocket;
@@ -163,8 +164,8 @@
 
         String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites();
         c.serverSocket.setEnabledCipherSuites(supportedCipherSuites);
-        LinkedList<String> uniqueCipherSuites =
-                new LinkedList<String>(Arrays.asList(supportedCipherSuites));
+        Deque<String> uniqueCipherSuites =
+                new ArrayDeque<String>(Arrays.asList(supportedCipherSuites));
         // only use RSA cipher suites which will work with our TrustProvider
         Iterator<String> i = uniqueCipherSuites.iterator();
         while (i.hasNext()) {
@@ -202,9 +203,9 @@
          * session cache.
          */
         assertTrue(uniqueCipherSuites.size() >= 3);
-        String cipherSuite1 = uniqueCipherSuites.get(0);
-        String cipherSuite2 = uniqueCipherSuites.get(1);
-        String cipherSuite3 = uniqueCipherSuites.get(2);
+        String cipherSuite1 = uniqueCipherSuites.pop();
+        String cipherSuite2 = uniqueCipherSuites.pop();
+        String cipherSuite3 = uniqueCipherSuites.pop();
 
         List<SSLSocket[]> toClose = new ArrayList<SSLSocket[]>();
         toClose.add(
diff --git a/openjdk/src/test/java/org/conscrypt/ConscryptSocketTest.java b/openjdk/src/test/java/org/conscrypt/ConscryptSocketTest.java
index 9deb949..cffb5a4 100644
--- a/openjdk/src/test/java/org/conscrypt/ConscryptSocketTest.java
+++ b/openjdk/src/test/java/org/conscrypt/ConscryptSocketTest.java
@@ -544,21 +544,45 @@
         assertThat(connection.clientException.getCause(), instanceOf(CertificateException.class));
     }
 
+    @Test
+    @SuppressWarnings("deprecation")
+    public void setAlpnProtocolWithNullShouldSucceed() throws Exception {
+        ServerSocket listening = newServerSocket();
+        OpenSSLSocketImpl clientSocket = null;
+        try {
+            Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+            clientSocket = (OpenSSLSocketImpl) socketType.newClientSocket(
+                    new ClientHooks().createContext(), listening, underlying);
+
+            // Both versions should succeed.
+            clientSocket.setAlpnProtocols((byte[]) null);
+            clientSocket.setAlpnProtocols((String[]) null);
+        } finally {
+            if (clientSocket != null) {
+                clientSocket.close();
+            }
+            listening.close();
+        }
+    }
+
     // http://b/27250522
     @Test
     public void test_setSoTimeout_doesNotCreateSocketImpl() throws Exception {
         ServerSocket listening = newServerSocket();
-        Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+        try {
+            Socket underlying = new Socket(listening.getInetAddress(), listening.getLocalPort());
+            Socket socket = socketType.newClientSocket(
+                    new ClientHooks().createContext(), listening, underlying);
+            socketType.assertSocketType(socket);
+            socket.setSoTimeout(1000);
+            socket.close();
 
-        Socket socket = socketType.newClientSocket(
-                new ClientHooks().createContext(), listening, underlying);
-        socketType.assertSocketType(socket);
-        socket.setSoTimeout(1000);
-        socket.close();
-
-        Field f = Socket.class.getDeclaredField("created");
-        f.setAccessible(true);
-        assertFalse(f.getBoolean(socket));
+            Field f = Socket.class.getDeclaredField("created");
+            f.setAccessible(true);
+            assertFalse(f.getBoolean(socket));
+        } finally {
+            listening.close();
+        }
     }
 
     @Test
diff --git a/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java b/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
index 1c014cb..5576325 100644
--- a/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
+++ b/openjdk/src/test/java/org/conscrypt/SSLUtilsTest.java
@@ -66,6 +66,16 @@
         assertArrayEquals(expected, actual);
     }
 
+    @Test(expected = NullPointerException.class)
+    public void decodeNullProtocolsShouldThrow() {
+        SSLUtils.decodeProtocols(null);
+    }
+
+    @Test
+    public void decodeEmptyProtocolsShouldSucceed() {
+        assertArrayEquals(EmptyArray.STRING, SSLUtils.decodeProtocols(EmptyArray.BYTE));
+    }
+
     @Test
     public void decodeProtocolsShouldSucceed() {
         byte[][] protocols = new byte[][]{
diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java
index 7cdecad..d16393f 100644
--- a/platform/src/main/java/org/conscrypt/Platform.java
+++ b/platform/src/main/java/org/conscrypt/Platform.java
@@ -20,7 +20,6 @@
 import static android.system.OsConstants.SO_SNDTIMEO;
 
 import android.system.ErrnoException;
-import android.system.Os;
 import android.system.StructTimeval;
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
@@ -54,6 +53,7 @@
 import javax.net.ssl.StandardConstants;
 import javax.net.ssl.X509ExtendedTrustManager;
 import javax.net.ssl.X509TrustManager;
+import libcore.io.Libcore;
 import libcore.net.NetworkSecurityPolicy;
 import sun.security.x509.AlgorithmId;
 
@@ -110,7 +110,7 @@
     static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws SocketException {
         StructTimeval tv = StructTimeval.fromMillis(timeoutMillis);
         try {
-            Os.setsockoptTimeval(s.getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
+            Libcore.os.setsockoptTimeval(s.getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
         } catch (ErrnoException errnoException) {
             throw errnoException.rethrowAsSocketException();
         }
diff --git a/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java b/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java
index a6aadf2..0d9f94e 100644
--- a/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java
+++ b/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java
@@ -16,12 +16,13 @@
 
 package org.conscrypt.ct;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
-import java.io.StringBufferInputStream;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
@@ -39,6 +40,8 @@
  */
 @Internal
 public class CTLogStoreImpl implements CTLogStore {
+    private static final Charset US_ASCII = Charset.forName("US-ASCII");
+
     /**
      * Thrown when parsing of a log file fails.
      */
@@ -223,10 +226,10 @@
 
         PublicKey pubkey;
         try {
-            pubkey = InternalUtil.readPublicKeyPem(new StringBufferInputStream(
-                        "-----BEGIN PUBLIC KEY-----\n" +
+            pubkey = InternalUtil.readPublicKeyPem(new ByteArrayInputStream(
+                    ("-----BEGIN PUBLIC KEY-----\n" +
                         key + "\n" +
-                        "-----END PUBLIC KEY-----"));
+                        "-----END PUBLIC KEY-----").getBytes(US_ASCII)));
         } catch (InvalidKeyException e) {
             throw new InvalidLogFileException(e);
         } catch (NoSuchAlgorithmException e) {
@@ -242,7 +245,7 @@
     };
 
     private static String hexEncode(byte[] data) {
-        StringBuffer sb = new StringBuffer(data.length * 2);
+        StringBuilder sb = new StringBuilder(data.length * 2);
         for (byte b: data) {
             sb.append(HEX_DIGITS[(b >> 4) & 0x0f]);
             sb.append(HEX_DIGITS[b & 0x0f]);
diff --git a/testing/src/main/java/org/conscrypt/TestUtils.java b/testing/src/main/java/org/conscrypt/TestUtils.java
index 25bf071..6521261 100644
--- a/testing/src/main/java/org/conscrypt/TestUtils.java
+++ b/testing/src/main/java/org/conscrypt/TestUtils.java
@@ -55,9 +55,10 @@
 public final class TestUtils {
     public static final Charset UTF_8 = Charset.forName("UTF-8");
     private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+    private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
     private static final String PROTOCOL_TLS_V1 = "TLSv1";
     private static final String[] DESIRED_PROTOCOLS =
-        new String[] {PROTOCOL_TLS_V1_2, /* For Java 6 */ PROTOCOL_TLS_V1};
+        new String[] {PROTOCOL_TLS_V1_2, PROTOCOL_TLS_V1_1, /* For Java 6 */ PROTOCOL_TLS_V1};
     private static final Provider JDK_PROVIDER = getDefaultTlsProvider();
     private static final byte[] CHARS =
             "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".getBytes(UTF_8);