| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| /* |
| * Copyright (C) 2010 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 com.android.org.conscrypt; |
| |
| import static com.android.org.conscrypt.NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING; |
| import static com.android.org.conscrypt.NativeConstants.SSL_MODE_ENABLE_FALSE_START; |
| import static com.android.org.conscrypt.NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE; |
| import static com.android.org.conscrypt.NativeConstants.SSL_OP_NO_TICKET; |
| import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
| import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_NONE; |
| import static com.android.org.conscrypt.NativeConstants.SSL_VERIFY_PEER; |
| import static com.android.org.conscrypt.NativeConstants.TLS1_1_VERSION; |
| import static com.android.org.conscrypt.NativeConstants.TLS1_2_VERSION; |
| import static com.android.org.conscrypt.NativeConstants.TLS1_VERSION; |
| import static com.android.org.conscrypt.TestUtils.openTestFile; |
| import static com.android.org.conscrypt.TestUtils.readTestFile; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNotSame; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.Matchers.same; |
| import static org.mockito.Mockito.when; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileDescriptor; |
| import java.io.IOException; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.Method; |
| import java.math.BigInteger; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import java.net.SocketTimeoutException; |
| import java.security.KeyPair; |
| import java.security.KeyPairGenerator; |
| import java.security.KeyStore; |
| import java.security.KeyStore.PrivateKeyEntry; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateEncodingException; |
| import java.security.cert.CertificateException; |
| import java.security.cert.X509Certificate; |
| import java.security.interfaces.ECPublicKey; |
| import java.security.interfaces.RSAPrivateCrtKey; |
| import java.security.interfaces.RSAPublicKey; |
| import java.security.spec.ECPrivateKeySpec; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| import javax.net.ssl.SSLEngine; |
| import javax.net.ssl.SSLException; |
| import javax.net.ssl.SSLHandshakeException; |
| import javax.net.ssl.SSLProtocolException; |
| import javax.security.auth.x500.X500Principal; |
| import com.android.org.conscrypt.NativeCrypto.SSLHandshakeCallbacks; |
| import com.android.org.conscrypt.OpenSSLX509CertificateFactory.ParsingException; |
| import com.android.org.conscrypt.io.IoUtils; |
| import com.android.org.conscrypt.java.security.StandardNames; |
| import com.android.org.conscrypt.java.security.TestKeyStore; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.mockito.Matchers; |
| import org.mockito.Mockito; |
| |
| /** |
| * @hide This class is not part of the Android public SDK API |
| */ |
| @RunWith(JUnit4.class) |
| public class NativeCryptoTest { |
| private static final long NULL = 0; |
| private static final FileDescriptor INVALID_FD = new FileDescriptor(); |
| private static final SSLHandshakeCallbacks DUMMY_CB = |
| new TestSSLHandshakeCallbacks(null, 0, null); |
| |
| private static final long TIMEOUT_SECONDS = 5; |
| |
| private static OpenSSLKey SERVER_PRIVATE_KEY; |
| private static OpenSSLX509Certificate[] SERVER_CERTIFICATES_HOLDER; |
| private static long[] SERVER_CERTIFICATE_REFS; |
| private static byte[][] ENCODED_SERVER_CERTIFICATES; |
| private static OpenSSLKey CLIENT_PRIVATE_KEY; |
| private static OpenSSLX509Certificate[] CLIENT_CERTIFICATES_HOLDER; |
| private static long[] CLIENT_CERTIFICATE_REFS; |
| private static byte[][] ENCODED_CLIENT_CERTIFICATES; |
| private static byte[][] CA_PRINCIPALS; |
| private static OpenSSLKey CHANNEL_ID_PRIVATE_KEY; |
| private static byte[] CHANNEL_ID; |
| private static Method m_Platform_getFileDescriptor; |
| |
| @BeforeClass |
| public static void getPlatformMethods() throws Exception { |
| Class<?> c_Platform = TestUtils.conscryptClass("Platform"); |
| m_Platform_getFileDescriptor = |
| c_Platform.getDeclaredMethod("getFileDescriptor", Socket.class); |
| m_Platform_getFileDescriptor.setAccessible(true); |
| } |
| |
| private static OpenSSLKey getServerPrivateKey() { |
| initCerts(); |
| return SERVER_PRIVATE_KEY; |
| } |
| |
| private static long[] getServerCertificateRefs() { |
| initCerts(); |
| return SERVER_CERTIFICATE_REFS; |
| } |
| |
| private static byte[][] getEncodedServerCertificates() { |
| initCerts(); |
| return ENCODED_SERVER_CERTIFICATES; |
| } |
| |
| private static OpenSSLKey getClientPrivateKey() { |
| initCerts(); |
| return CLIENT_PRIVATE_KEY; |
| } |
| |
| private static long[] getClientCertificateRefs() { |
| initCerts(); |
| return CLIENT_CERTIFICATE_REFS; |
| } |
| |
| private static byte[][] getEncodedClientCertificates() { |
| initCerts(); |
| return ENCODED_CLIENT_CERTIFICATES; |
| } |
| |
| private static byte[][] getCaPrincipals() { |
| initCerts(); |
| return CA_PRINCIPALS; |
| } |
| |
| /** |
| * Lazily create shared test certificates. |
| */ |
| private static synchronized void initCerts() { |
| if (SERVER_PRIVATE_KEY != null) { |
| return; |
| } |
| |
| try { |
| PrivateKeyEntry serverPrivateKeyEntry = |
| TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); |
| SERVER_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(serverPrivateKeyEntry.getPrivateKey()); |
| SERVER_CERTIFICATES_HOLDER = |
| encodeCertificateList(serverPrivateKeyEntry.getCertificateChain()); |
| SERVER_CERTIFICATE_REFS = getCertificateReferences(SERVER_CERTIFICATES_HOLDER); |
| ENCODED_SERVER_CERTIFICATES = getEncodedCertificates(SERVER_CERTIFICATES_HOLDER); |
| |
| PrivateKeyEntry clientPrivateKeyEntry = |
| TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA"); |
| CLIENT_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(clientPrivateKeyEntry.getPrivateKey()); |
| CLIENT_CERTIFICATES_HOLDER = |
| encodeCertificateList(clientPrivateKeyEntry.getCertificateChain()); |
| CLIENT_CERTIFICATE_REFS = getCertificateReferences(CLIENT_CERTIFICATES_HOLDER); |
| ENCODED_CLIENT_CERTIFICATES = getEncodedCertificates(CLIENT_CERTIFICATES_HOLDER); |
| |
| KeyStore ks = TestKeyStore.getClient().keyStore; |
| String caCertAlias = ks.aliases().nextElement(); |
| X509Certificate certificate = (X509Certificate) ks.getCertificate(caCertAlias); |
| X500Principal principal = certificate.getIssuerX500Principal(); |
| CA_PRINCIPALS = new byte[][] {principal.getEncoded()}; |
| initChannelIdKey(); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private static long[] getCertificateReferences(OpenSSLX509Certificate[] certs) { |
| final long[] certRefs = new long[certs.length]; |
| for (int i = 0; i < certs.length; i++) { |
| certRefs[i] = certs[i].getContext(); |
| } |
| return certRefs; |
| } |
| |
| private static byte[][] getEncodedCertificates(OpenSSLX509Certificate[] certs) { |
| try { |
| final byte[][] encoded = new byte[certs.length][]; |
| for (int i = 0; i < certs.length; i++) { |
| encoded[i] = certs[i].getEncoded(); |
| } |
| return encoded; |
| } catch (CertificateEncodingException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private static OpenSSLX509Certificate[] encodeCertificateList(Certificate[] chain) |
| throws CertificateEncodingException { |
| final OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[chain.length]; |
| for (int i = 0; i < chain.length; i++) { |
| openSslCerts[i] = OpenSSLX509Certificate.fromCertificate(chain[i]); |
| } |
| return openSslCerts; |
| } |
| |
| private static synchronized void initChannelIdKey() throws Exception { |
| if (CHANNEL_ID_PRIVATE_KEY != null) { |
| return; |
| } |
| |
| // NIST P-256 aka SECG secp256r1 aka X9.62 prime256v1 |
| OpenSSLECGroupContext openSslSpec = OpenSSLECGroupContext.getCurveByName("prime256v1"); |
| BigInteger s = new BigInteger( |
| "229cdbbf489aea584828a261a23f9ff8b0f66f7ccac98bf2096ab3aee41497c5", 16); |
| CHANNEL_ID_PRIVATE_KEY = |
| new OpenSSLECPrivateKey(new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec())) |
| .getOpenSSLKey(); |
| |
| // Channel ID is the concatenation of the X and Y coordinates of the public key. |
| CHANNEL_ID = new BigInteger( |
| "702b07871fd7955c320b26f15e244e47eed60272124c92b9ebecf0b42f90069b" |
| + "ab53592ebfeb4f167dbf3ce61513afb0e354c479b1c1b69874fa471293494f77", |
| 16).toByteArray(); |
| } |
| |
| private static RSAPrivateCrtKey generateRsaKey() throws Exception { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); |
| kpg.initialize(512); |
| |
| KeyPair keyPair = kpg.generateKeyPair(); |
| return (RSAPrivateCrtKey) keyPair.getPrivate(); |
| } |
| |
| private static NativeRef.EVP_PKEY getRsaPkey(RSAPrivateCrtKey privKey) throws Exception { |
| return new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA( |
| privKey.getModulus().toByteArray(), privKey.getPublicExponent().toByteArray(), |
| privKey.getPrivateExponent().toByteArray(), privKey.getPrimeP().toByteArray(), |
| privKey.getPrimeQ().toByteArray(), privKey.getPrimeExponentP().toByteArray(), |
| privKey.getPrimeExponentQ().toByteArray(), |
| privKey.getCrtCoefficient().toByteArray())); |
| } |
| |
| public static void assertEqualSessions(long expected, long actual) { |
| assertEqualByteArrays(NativeCrypto.SSL_SESSION_session_id(expected), |
| NativeCrypto.SSL_SESSION_session_id(actual)); |
| } |
| public static void assertEqualByteArrays(byte[] expected, byte[] actual) { |
| assertEquals(Arrays.toString(expected), Arrays.toString(actual)); |
| } |
| |
| public static void assertEqualPrincipals(byte[][] expected, byte[][] actual) { |
| assertEqualByteArrays(expected, actual); |
| } |
| |
| public static void assertEqualCertificateChains(long[] expected, long[] actual) { |
| assertEquals(expected.length, actual.length); |
| for (int i = 0; i < expected.length; i++) { |
| NativeCrypto.X509_cmp(expected[i], null, actual[i], null); |
| } |
| } |
| |
| public static void assertEqualByteArrays(byte[][] expected, byte[][] actual) { |
| assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual)); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_cmp_BothNullParameters() throws Exception { |
| NativeCrypto.EVP_PKEY_cmp(null, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_cmp_withNullShouldThrow() throws Exception { |
| RSAPrivateCrtKey privKey1 = generateRsaKey(); |
| NativeRef.EVP_PKEY pkey1 = getRsaPkey(privKey1); |
| assertNotSame(NULL, pkey1); |
| NativeCrypto.EVP_PKEY_cmp(pkey1, null); |
| } |
| |
| @Test |
| public void test_EVP_PKEY_cmp() throws Exception { |
| RSAPrivateCrtKey privKey1 = generateRsaKey(); |
| |
| NativeRef.EVP_PKEY pkey1 = getRsaPkey(privKey1); |
| assertNotSame(NULL, pkey1); |
| |
| NativeRef.EVP_PKEY pkey1_copy = getRsaPkey(privKey1); |
| assertNotSame(NULL, pkey1_copy); |
| |
| NativeRef.EVP_PKEY pkey2 = getRsaPkey(generateRsaKey()); |
| assertNotSame(NULL, pkey2); |
| |
| assertEquals("Same keys should be the equal", 1, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1)); |
| |
| assertEquals( |
| "Same keys should be the equal", 1, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1_copy)); |
| |
| assertEquals( |
| "Different keys should not be equal", 0, NativeCrypto.EVP_PKEY_cmp(pkey1, pkey2)); |
| } |
| |
| @Test |
| public void test_SSL_CTX_new() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| assertTrue(c != NULL); |
| long c2 = NativeCrypto.SSL_CTX_new(); |
| assertTrue(c != c2); |
| NativeCrypto.SSL_CTX_free(c, null); |
| NativeCrypto.SSL_CTX_free(c2, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_CTX_free_NullArgument() throws Exception { |
| NativeCrypto.SSL_CTX_free(NULL, null); |
| } |
| |
| @Test |
| public void test_SSL_CTX_free() throws Exception { |
| NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new(), null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_CTX_set_session_id_context_NullContextArgument() throws Exception { |
| NativeCrypto.SSL_CTX_set_session_id_context(NULL, null, new byte[0]); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_CTX_set_session_id_context_withNullShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| try { |
| NativeCrypto.SSL_CTX_set_session_id_context(c, null, null); |
| } finally { |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void test_SSL_CTX_set_session_id_context_withInvalidIdShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| try { |
| NativeCrypto.SSL_CTX_set_session_id_context(c, null, new byte[33]); |
| } finally { |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_CTX_set_session_id_context() throws Exception { |
| byte[] empty = new byte[0]; |
| |
| long c = NativeCrypto.SSL_CTX_new(); |
| try { |
| NativeCrypto.SSL_CTX_set_session_id_context(c, null, empty); |
| NativeCrypto.SSL_CTX_set_session_id_context(c, null, new byte[32]); |
| } finally { |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_new() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| assertTrue(s != NULL); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_NO_TICKET) != 0); |
| |
| long s2 = NativeCrypto.SSL_new(c, null); |
| assertTrue(s != s2); |
| NativeCrypto.SSL_free(s2, null); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void setLocalCertsAndPrivateKey_withNullSSLShouldThrow() throws Exception { |
| NativeCrypto.setLocalCertsAndPrivateKey( |
| NULL, null, getEncodedServerCertificates(), getServerPrivateKey().getNativeRef()); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void setLocalCertsAndPrivateKey_withNullCertificatesShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.setLocalCertsAndPrivateKey(s, null, null, getServerPrivateKey().getNativeRef()); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void setLocalCertsAndPrivateKey_withNullKeyShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.setLocalCertsAndPrivateKey(s, null, getEncodedServerCertificates(), null); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void setLocalCertsAndPrivateKey() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| NativeCrypto.setLocalCertsAndPrivateKey( |
| s, null, getEncodedServerCertificates(), getServerPrivateKey().getNativeRef()); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set1_tls_channel_id_withNullChannelShouldThrow() throws Exception { |
| NativeCrypto.SSL_set1_tls_channel_id(NULL, null, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set1_tls_channel_id_withNullKeyShouldThrow() throws Exception { |
| initChannelIdKey(); |
| |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_set1_tls_channel_id(s, null, null); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception { |
| initChannelIdKey(); |
| |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| // Use the key natively. This works because the initChannelIdKey method ensures that the |
| // key is backed by OpenSSL. |
| NativeCrypto.SSL_set1_tls_channel_id(s, null, CHANNEL_ID_PRIVATE_KEY.getNativeRef()); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_get_mode_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_get_mode(NULL, null); |
| } |
| |
| @Test |
| public void test_SSL_get_mode() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertTrue(NativeCrypto.SSL_get_mode(s, null) != 0); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_mode_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_mode(NULL, null, 0); |
| } |
| |
| @Test |
| public void test_SSL_set_mode_and_clear_mode() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| // check SSL_MODE_ENABLE_FALSE_START on by default for BoringSSL |
| assertEquals(SSL_MODE_ENABLE_FALSE_START, |
| NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START); |
| // check SSL_MODE_CBC_RECORD_SPLITTING off by default |
| assertEquals(0, NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_CBC_RECORD_SPLITTING); |
| |
| // set SSL_MODE_ENABLE_FALSE_START on |
| NativeCrypto.SSL_set_mode(s, null, SSL_MODE_ENABLE_FALSE_START); |
| assertTrue((NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START) != 0); |
| // clear SSL_MODE_ENABLE_FALSE_START off |
| NativeCrypto.SSL_clear_mode(s, null, SSL_MODE_ENABLE_FALSE_START); |
| assertTrue((NativeCrypto.SSL_get_mode(s, null) & SSL_MODE_ENABLE_FALSE_START) == 0); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_get_options_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_get_options(NULL, null); |
| } |
| |
| @Test |
| public void test_SSL_get_options() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertTrue(NativeCrypto.SSL_get_options(s, null) != 0); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_options_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_options(NULL, null, 0); |
| } |
| |
| @Test |
| public void test_SSL_set_options() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0); |
| NativeCrypto.SSL_set_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_clear_options_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_clear_options(NULL, null, 0); |
| } |
| |
| @Test |
| public void test_SSL_clear_options() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0); |
| NativeCrypto.SSL_set_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0); |
| NativeCrypto.SSL_clear_options(s, null, SSL_OP_CIPHER_SERVER_PREFERENCE); |
| assertTrue((NativeCrypto.SSL_get_options(s, null) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_protocol_versions_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_protocol_versions(NULL, null, 0, 0); |
| } |
| |
| @Test |
| public void SSL_set_protocol_versions() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertEquals(1, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_VERSION, TLS1_1_VERSION)); |
| assertEquals(1, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_2_VERSION, TLS1_2_VERSION)); |
| assertEquals(0, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_2_VERSION + 413, TLS1_1_VERSION)); |
| assertEquals(0, NativeCrypto.SSL_set_protocol_versions(s, null, TLS1_1_VERSION, TLS1_2_VERSION + 413)); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_cipher_lists_withNullSslShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_cipher_lists(NULL, null, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_cipher_lists_withNullCiphersShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_set_cipher_lists(s, null, null); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_set_cipher_lists_withNullCipherShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {null}); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void SSL_set_cipher_lists_withEmptyCiphersShouldSucceed() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| // Explicitly checking that the empty list is allowed. |
| // b/21816861 |
| NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {}); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test |
| public void SSL_set_cipher_lists_withIllegalCipherShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| // see OpenSSL ciphers man page |
| String[] illegals = new String[] {// empty |
| "", |
| // never standardized |
| "EXP1024-DES-CBC-SHA", |
| // IDEA |
| "IDEA-CBC-SHA", "IDEA-CBC-MD5"}; |
| |
| for (String illegal : illegals) { |
| try { |
| NativeCrypto.SSL_set_cipher_lists(s, null, new String[] {illegal}); |
| fail("Exception now thrown for illegal cipher: " + illegal); |
| } catch (IllegalArgumentException expected) { |
| // Expected. |
| } |
| } |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test |
| public void SSL_set_cipher_lists_withValidCiphersShouldSucceed() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| List<String> ciphers = new ArrayList<String>(NativeCrypto.SUPPORTED_TLS_1_2_CIPHER_SUITES_SET); |
| NativeCrypto.SSL_set_cipher_lists(s, null, ciphers.toArray(new String[ciphers.size()])); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_verify_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_verify(NULL, null, 0); |
| } |
| |
| @Test |
| public void test_SSL_set_verify() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_NONE); |
| NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_PEER); |
| NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_FAIL_IF_NO_PEER_CERT); |
| NativeCrypto.SSL_set_verify(s, null, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT)); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| private static final boolean DEBUG = false; |
| |
| /** |
| * @hide This class is not part of the Android public SDK API |
| */ |
| public static class Hooks { |
| String negotiatedCipherSuite; |
| private OpenSSLKey channelIdPrivateKey; |
| boolean pskEnabled; |
| byte[] pskKey; |
| List<String> enabledCipherSuites; |
| |
| /** |
| * @throws SSLException if an error occurs creating the context. |
| */ |
| public long getContext() throws SSLException { |
| return NativeCrypto.SSL_CTX_new(); |
| } |
| |
| public long beforeHandshake(long context) throws SSLException { |
| long s = NativeCrypto.SSL_new(context, null); |
| // Limit cipher suites to a known set so authMethod is known. |
| List<String> cipherSuites = new ArrayList<String>(); |
| if (enabledCipherSuites == null) { |
| cipherSuites.add("ECDHE-RSA-AES128-SHA"); |
| if (pskEnabled) { |
| // In TLS-PSK the client indicates that PSK key exchange is desired by offering |
| // at least one PSK cipher suite. |
| cipherSuites.add(0, "PSK-AES128-CBC-SHA"); |
| } |
| } else { |
| cipherSuites.addAll(enabledCipherSuites); |
| } |
| // Protocol list is included for determining whether to send TLS_FALLBACK_SCSV |
| NativeCrypto.setEnabledCipherSuites(s, null, |
| cipherSuites.toArray(new String[cipherSuites.size()]), |
| new String[] {"TLSv1.2"}); |
| |
| if (channelIdPrivateKey != null) { |
| NativeCrypto.SSL_set1_tls_channel_id(s, null, channelIdPrivateKey.getNativeRef()); |
| } |
| return s; |
| } |
| public void configureCallbacks( |
| @SuppressWarnings("unused") TestSSLHandshakeCallbacks callbacks) {} |
| public void clientCertificateRequested(@SuppressWarnings("unused") long s) |
| throws CertificateEncodingException, SSLException {} |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| if (session != NULL) { |
| negotiatedCipherSuite = NativeCrypto.SSL_SESSION_cipher(session); |
| NativeCrypto.SSL_SESSION_free(session); |
| } |
| if (ssl != NULL) { |
| try { |
| NativeCrypto.SSL_shutdown(ssl, null, fd, callback); |
| } catch (IOException e) { |
| // Expected. |
| } |
| NativeCrypto.SSL_free(ssl, null); |
| } |
| if (context != NULL) { |
| NativeCrypto.SSL_CTX_free(context, null); |
| } |
| if (socket != null) { |
| socket.close(); |
| } |
| } |
| } |
| |
| static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks { |
| private final Socket socket; |
| private final long sslNativePointer; |
| private final Hooks hooks; |
| |
| TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks) { |
| this.socket = socket; |
| this.sslNativePointer = sslNativePointer; |
| this.hooks = hooks; |
| } |
| |
| private long[] certificateChainRefs; |
| private String authMethod; |
| private boolean verifyCertificateChainCalled; |
| |
| @Override |
| public void verifyCertificateChain(byte[][] certs, String authMethod) |
| throws CertificateException { |
| certificateChainRefs = new long[certs.length]; |
| for (int i = 0; i < certs.length; ++i) { |
| byte[] cert = certs[i]; |
| try { |
| certificateChainRefs[i] = NativeCrypto.d2i_X509(cert); |
| } catch (ParsingException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| this.authMethod = authMethod; |
| this.verifyCertificateChainCalled = true; |
| } |
| |
| private byte[] keyTypes; |
| private int[] signatureAlgs; |
| private byte[][] asn1DerEncodedX500Principals; |
| private boolean clientCertificateRequestedCalled; |
| |
| @Override |
| public void clientCertificateRequested( |
| byte[] keyTypes, int[] signatureAlgs, byte[][] asn1DerEncodedX500Principals) |
| throws CertificateEncodingException, SSLException { |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) |
| + " clientCertificateRequested" |
| + " keyTypes=" + Arrays.toString(keyTypes) |
| + " asn1DerEncodedX500Principals=" |
| + Arrays.toString(asn1DerEncodedX500Principals)); |
| } |
| this.keyTypes = keyTypes; |
| this.signatureAlgs = signatureAlgs; |
| this.asn1DerEncodedX500Principals = asn1DerEncodedX500Principals; |
| this.clientCertificateRequestedCalled = true; |
| if (hooks != null) { |
| hooks.clientCertificateRequested(sslNativePointer); |
| } |
| } |
| |
| private boolean handshakeCompletedCalled; |
| |
| @Override |
| public void onSSLStateChange(int type, int val) { |
| if (DEBUG) { |
| System.out.println( |
| "ssl=0x" + Long.toString(sslNativePointer, 16) + " onSSLStateChange"); |
| } |
| this.handshakeCompletedCalled = true; |
| } |
| |
| Socket getSocket() { |
| return socket; |
| } |
| |
| private boolean clientPSKKeyRequestedInvoked; |
| private String clientPSKKeyRequestedIdentityHint; |
| private int clientPSKKeyRequestedResult; |
| private byte[] clientPSKKeyRequestedResultKey; |
| private byte[] clientPSKKeyRequestedResultIdentity; |
| |
| @Override |
| public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) { |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) |
| + " clientPSKKeyRequested" |
| + " identityHint=" + identityHint + " identity capacity=" + identity.length |
| + " key capacity=" + key.length); |
| } |
| clientPSKKeyRequestedInvoked = true; |
| clientPSKKeyRequestedIdentityHint = identityHint; |
| if (clientPSKKeyRequestedResultKey != null) { |
| System.arraycopy(clientPSKKeyRequestedResultKey, 0, key, 0, |
| clientPSKKeyRequestedResultKey.length); |
| } |
| if (clientPSKKeyRequestedResultIdentity != null) { |
| System.arraycopy(clientPSKKeyRequestedResultIdentity, 0, identity, 0, |
| Math.min(clientPSKKeyRequestedResultIdentity.length, identity.length)); |
| } |
| return clientPSKKeyRequestedResult; |
| } |
| |
| private boolean serverPSKKeyRequestedInvoked; |
| private int serverPSKKeyRequestedResult; |
| private byte[] serverPSKKeyRequestedResultKey; |
| private String serverPSKKeyRequestedIdentityHint; |
| private String serverPSKKeyRequestedIdentity; |
| |
| @Override |
| public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) { |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) |
| + " serverPSKKeyRequested" |
| + " identityHint=" + identityHint + " identity=" + identity |
| + " key capacity=" + key.length); |
| } |
| serverPSKKeyRequestedInvoked = true; |
| serverPSKKeyRequestedIdentityHint = identityHint; |
| serverPSKKeyRequestedIdentity = identity; |
| if (serverPSKKeyRequestedResultKey != null) { |
| System.arraycopy(serverPSKKeyRequestedResultKey, 0, key, 0, |
| serverPSKKeyRequestedResultKey.length); |
| } |
| return serverPSKKeyRequestedResult; |
| } |
| |
| private boolean onNewSessionEstablishedInvoked; |
| private boolean onNewSessionEstablishedSaveSession; |
| private long onNewSessionEstablishedSessionNativePointer; |
| |
| @Override |
| public void onNewSessionEstablished(long sslSessionNativePtr) { |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) |
| + " onNewSessionCreated" |
| + " ssl=0x" + Long.toString(sslSessionNativePtr, 16)); |
| } |
| onNewSessionEstablishedInvoked = true; |
| |
| if (onNewSessionEstablishedSaveSession) { |
| NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr); |
| onNewSessionEstablishedSessionNativePointer = sslSessionNativePtr; |
| } |
| } |
| |
| @Override |
| public long serverSessionRequested(byte[] id) { |
| // TODO(nathanmittler): Implement server-side caching for TLS < 1.3 |
| return 0; |
| } |
| } |
| |
| static class ClientHooks extends Hooks { |
| private String pskIdentity; |
| |
| @Override |
| public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) { |
| super.configureCallbacks(callbacks); |
| if (pskEnabled) { |
| if (pskIdentity != null) { |
| // Create a NULL-terminated modified UTF-8 representation of pskIdentity. |
| byte[] b; |
| try { |
| b = pskIdentity.getBytes("UTF-8"); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException("UTF-8 encoding not supported", e); |
| } |
| callbacks.clientPSKKeyRequestedResultIdentity = Arrays.copyOf(b, b.length + 1); |
| } |
| callbacks.clientPSKKeyRequestedResultKey = pskKey; |
| callbacks.clientPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0; |
| } |
| } |
| |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| if (pskEnabled) { |
| NativeCrypto.set_SSL_psk_client_callback_enabled(s, null, true); |
| } |
| return s; |
| } |
| } |
| |
| static class ServerHooks extends Hooks { |
| private final OpenSSLKey privateKey; |
| private final byte[][] certificates; |
| private boolean channelIdEnabled; |
| private byte[] channelIdAfterHandshake; |
| private Throwable channelIdAfterHandshakeException; |
| |
| private String pskIdentityHint; |
| |
| public ServerHooks() { |
| this(null, null); |
| } |
| |
| ServerHooks(OpenSSLKey privateKey, byte[][] certificates) { |
| this.privateKey = privateKey; |
| this.certificates = certificates; |
| } |
| |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| if (privateKey != null && certificates != null) { |
| NativeCrypto.setLocalCertsAndPrivateKey(s, null, certificates, privateKey.getNativeRef()); |
| } |
| if (channelIdEnabled) { |
| NativeCrypto.SSL_enable_tls_channel_id(s, null); |
| } |
| if (pskEnabled) { |
| NativeCrypto.set_SSL_psk_server_callback_enabled(s, null, true); |
| NativeCrypto.SSL_use_psk_identity_hint(s, null, pskIdentityHint); |
| } |
| NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_NONE); |
| return s; |
| } |
| |
| @Override |
| public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) { |
| super.configureCallbacks(callbacks); |
| if (pskEnabled) { |
| callbacks.serverPSKKeyRequestedResultKey = pskKey; |
| callbacks.serverPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0; |
| } |
| } |
| |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| if (channelIdEnabled) { |
| try { |
| channelIdAfterHandshake = NativeCrypto.SSL_get_tls_channel_id(ssl, null); |
| } catch (Exception e) { |
| channelIdAfterHandshakeException = e; |
| } |
| } |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| |
| @Override |
| public void clientCertificateRequested(long s) { |
| fail("Server asked for client certificates"); |
| } |
| } |
| |
| public static Future<TestSSLHandshakeCallbacks> handshake(final ServerSocket listener, |
| final int timeout, final boolean client, final Hooks hooks, final byte[] alpnProtocols, |
| final ApplicationProtocolSelectorAdapter alpnSelector) { |
| ExecutorService executor = Executors.newSingleThreadExecutor(); |
| Future<TestSSLHandshakeCallbacks> future = |
| executor.submit(new Callable<TestSSLHandshakeCallbacks>() { |
| @Override |
| public TestSSLHandshakeCallbacks call() throws Exception { |
| @SuppressWarnings("resource") |
| // Socket needs to remain open after the handshake |
| Socket socket = (client ? new Socket(listener.getInetAddress(), |
| listener.getLocalPort()) |
| : listener.accept()); |
| if (timeout == -1) { |
| return new TestSSLHandshakeCallbacks(socket, 0, null); |
| } |
| FileDescriptor fd = |
| (FileDescriptor) m_Platform_getFileDescriptor.invoke( |
| null, socket); |
| long c = hooks.getContext(); |
| long s = hooks.beforeHandshake(c); |
| TestSSLHandshakeCallbacks callback = |
| new TestSSLHandshakeCallbacks(socket, s, hooks); |
| hooks.configureCallbacks(callback); |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(s, 16) + " handshake" |
| + " context=0x" + Long.toString(c, 16) + " socket=" + socket |
| + " fd=0x" + Long.toString(System.identityHashCode(fd), 16) |
| + " timeout=" + timeout + " client=" + client); |
| } |
| long session = NULL; |
| try { |
| if (client) { |
| NativeCrypto.SSL_set_connect_state(s, null); |
| } else { |
| NativeCrypto.SSL_set_accept_state(s, null); |
| } |
| if (alpnProtocols != null) { |
| NativeCrypto.setApplicationProtocols(s, null, client, alpnProtocols); |
| } |
| if (!client && alpnSelector != null) { |
| NativeCrypto.setApplicationProtocolSelector(s, null, alpnSelector); |
| } |
| NativeCrypto.SSL_do_handshake(s, null, fd, callback, timeout); |
| session = NativeCrypto.SSL_get1_session(s, null); |
| if (DEBUG) { |
| System.out.println("ssl=0x" + Long.toString(s, 16) |
| + " handshake" |
| + " session=0x" + Long.toString(session, 16)); |
| } |
| } finally { |
| // Ensure afterHandshake is called to free resources |
| hooks.afterHandshake(session, s, c, socket, fd, callback); |
| } |
| return callback; |
| } |
| }); |
| executor.shutdown(); |
| return future; |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_do_handshake_NULL_SSL() throws Exception { |
| NativeCrypto.SSL_do_handshake(NULL, null, null, null, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_do_handshake_withNullFdShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_set_connect_state(s, null); |
| try { |
| NativeCrypto.SSL_do_handshake(s, null, null, null, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_do_handshake_withNullShcShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_set_connect_state(s, null); |
| try { |
| NativeCrypto.SSL_do_handshake(s, null, INVALID_FD, null, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_normal() throws Exception { |
| // normal client and server case |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback.authMethod); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertFalse(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_reusedSession() throws Exception { |
| // normal client and server case |
| final ServerSocket listener = newServerSocket(); |
| |
| Future<TestSSLHandshakeCallbacks> client1 = handshake(listener, 0, true, new ClientHooks() { |
| @Override |
| public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) { |
| callbacks.onNewSessionEstablishedSaveSession = true; |
| } |
| }, null, null); |
| Future<TestSSLHandshakeCallbacks> server1 = handshake(listener, 0, |
| false, new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) { |
| callbacks.onNewSessionEstablishedSaveSession = true; |
| } |
| }, null, null); |
| TestSSLHandshakeCallbacks clientCallback1 = client1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback1 = server1.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback1.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback1.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback1.authMethod); |
| assertFalse(serverCallback1.verifyCertificateChainCalled); |
| assertFalse(clientCallback1.clientCertificateRequestedCalled); |
| assertFalse(serverCallback1.clientCertificateRequestedCalled); |
| assertFalse(clientCallback1.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback1.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback1.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback1.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback1.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback1.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback1.handshakeCompletedCalled); |
| assertTrue(serverCallback1.handshakeCompletedCalled); |
| |
| final long clientSessionContext = |
| clientCallback1.onNewSessionEstablishedSessionNativePointer; |
| final long serverSessionContext = |
| serverCallback1.onNewSessionEstablishedSessionNativePointer; |
| |
| Future<TestSSLHandshakeCallbacks> client2 = handshake(listener, 0, true, new ClientHooks() { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long sslNativePtr = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_session(sslNativePtr, null, clientSessionContext); |
| return sslNativePtr; |
| } |
| }, null, null); |
| Future<TestSSLHandshakeCallbacks> server2 = handshake(listener, 0, |
| false, new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long sslNativePtr = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_session(sslNativePtr, null, serverSessionContext); |
| return sslNativePtr; |
| } |
| }, null, null); |
| TestSSLHandshakeCallbacks clientCallback2 = client2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback2 = server2.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback2.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback2.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback2.authMethod); |
| assertFalse(serverCallback2.verifyCertificateChainCalled); |
| assertFalse(clientCallback2.clientCertificateRequestedCalled); |
| assertFalse(serverCallback2.clientCertificateRequestedCalled); |
| assertFalse(clientCallback2.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback2.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback2.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback2.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback2.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback2.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback2.handshakeCompletedCalled); |
| assertTrue(serverCallback2.handshakeCompletedCalled); |
| |
| NativeCrypto.SSL_SESSION_free(clientSessionContext); |
| NativeCrypto.SSL_SESSION_free(serverSessionContext); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_optional_client_certificate() throws Exception { |
| // optional client certificate case |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void clientCertificateRequested(long s) |
| throws CertificateEncodingException, SSLException { |
| super.clientCertificateRequested(s); |
| NativeCrypto.setLocalCertsAndPrivateKey( |
| s, null, getEncodedClientCertificates(), getClientPrivateKey().getNativeRef()); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_client_CA_list(s, null, getCaPrincipals()); |
| NativeCrypto.SSL_set_verify(s, null, SSL_VERIFY_PEER); |
| return s; |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback.authMethod); |
| assertTrue(serverCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getClientCertificateRefs(), serverCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", serverCallback.authMethod); |
| |
| assertTrue(clientCallback.clientCertificateRequestedCalled); |
| assertNotNull(clientCallback.keyTypes); |
| assertNotNull(clientCallback.signatureAlgs); |
| assertEquals(new HashSet<String>(Arrays.asList("EC", "RSA")), |
| SSLUtils.getSupportedClientKeyTypes( |
| clientCallback.keyTypes, clientCallback.signatureAlgs)); |
| assertEqualPrincipals(getCaPrincipals(), clientCallback.asn1DerEncodedX500Principals); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| |
| assertFalse(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_missing_required_certificate() throws Exception { |
| // required client certificate negative case |
| final ServerSocket listener = newServerSocket(); |
| try { |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_client_CA_list(s, null, getCaPrincipals()); |
| NativeCrypto.SSL_set_verify( |
| s, null, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); |
| return s; |
| } |
| }; |
| @SuppressWarnings("unused") |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_client_timeout() throws Exception { |
| // client timeout |
| final ServerSocket listener = newServerSocket(); |
| Socket serverSocket = null; |
| try { |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 1, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, -1, false, sHooks, null, null); |
| serverSocket = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); |
| } finally { |
| // Manually close peer socket when testing timeout |
| IoUtils.closeQuietly(serverSocket); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_server_timeout() throws Exception { |
| // server timeout |
| final ServerSocket listener = newServerSocket(); |
| Socket clientSocket = null; |
| try { |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, -1, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 1, false, sHooks, null, null); |
| clientSocket = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); |
| } finally { |
| // Manually close peer socket when testing timeout |
| IoUtils.closeQuietly(clientSocket); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_channel_id_normal() throws Exception { |
| initChannelIdKey(); |
| |
| // Normal handshake with TLS Channel ID. |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks(); |
| cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; |
| // TLS Channel ID currently requires ECDHE-based key exchanges. |
| cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA"); |
| ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| sHooks.channelIdEnabled = true; |
| sHooks.enabledCipherSuites = cHooks.enabledCipherSuites; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback.authMethod); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertFalse(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertNull(sHooks.channelIdAfterHandshakeException); |
| assertEqualByteArrays(CHANNEL_ID, sHooks.channelIdAfterHandshake); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_channel_id_not_supported_by_server() throws Exception { |
| initChannelIdKey(); |
| |
| // Client tries to use TLS Channel ID but the server does not enable/offer the extension. |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks(); |
| cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; |
| // TLS Channel ID currently requires ECDHE-based key exchanges. |
| cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA"); |
| ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| sHooks.channelIdEnabled = false; |
| sHooks.enabledCipherSuites = cHooks.enabledCipherSuites; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback.authMethod); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertFalse(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertNull(sHooks.channelIdAfterHandshakeException); |
| assertNull(sHooks.channelIdAfterHandshake); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_channel_id_not_enabled_by_client() throws Exception { |
| initChannelIdKey(); |
| |
| // Client does not use TLS Channel ID when the server has the extension enabled/offered. |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks(); |
| cHooks.channelIdPrivateKey = null; |
| // TLS Channel ID currently requires ECDHE-based key exchanges. |
| cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-SHA"); |
| ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| sHooks.channelIdEnabled = true; |
| sHooks.enabledCipherSuites = cHooks.enabledCipherSuites; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertTrue(clientCallback.verifyCertificateChainCalled); |
| assertEqualCertificateChains( |
| getServerCertificateRefs(), clientCallback.certificateChainRefs); |
| assertEquals("ECDHE_RSA", clientCallback.authMethod); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertFalse(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.serverPSKKeyRequestedInvoked); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertNull(sHooks.channelIdAfterHandshakeException); |
| assertNull(sHooks.channelIdAfterHandshake); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_psk_normal() throws Exception { |
| // normal TLS-PSK client and server case |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = cHooks.pskKey; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertFalse(clientCallback.verifyCertificateChainCalled); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertTrue(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertTrue(serverCallback.serverPSKKeyRequestedInvoked); |
| assertContains(cHooks.negotiatedCipherSuite, "PSK"); |
| assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite); |
| assertNull(clientCallback.clientPSKKeyRequestedIdentityHint); |
| assertNull(serverCallback.serverPSKKeyRequestedIdentityHint); |
| assertEquals("", serverCallback.serverPSKKeyRequestedIdentity); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_psk_with_identity_and_hint() throws Exception { |
| // normal TLS-PSK client and server case where the server provides the client with a PSK |
| // identity hint, and the client provides the server with a PSK identity. |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = cHooks.pskKey; |
| sHooks.pskIdentityHint = "Some non-ASCII characters: \u00c4\u0332"; |
| cHooks.pskIdentity = "More non-ASCII characters: \u00f5\u044b"; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertFalse(clientCallback.verifyCertificateChainCalled); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertTrue(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertTrue(serverCallback.serverPSKKeyRequestedInvoked); |
| assertContains(cHooks.negotiatedCipherSuite, "PSK"); |
| assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite); |
| assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint); |
| assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint); |
| assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity); |
| } |
| |
| @Test |
| @SuppressWarnings("deprecation") |
| public void test_SSL_do_handshake_with_psk_with_identity_and_hint_of_max_length() |
| throws Exception { |
| // normal TLS-PSK client and server case where the server provides the client with a PSK |
| // identity hint, and the client provides the server with a PSK identity. |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = cHooks.pskKey; |
| sHooks.pskIdentityHint = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" |
| + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"; |
| cHooks.pskIdentity = "123456789012345678901234567890123456789012345678901234567890" |
| + "12345678901234567890123456789012345678901234567890123456789012345678"; |
| assertEquals(PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES, sHooks.pskIdentityHint.length()); |
| assertEquals(PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES, cHooks.pskIdentity.length()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| assertFalse(clientCallback.verifyCertificateChainCalled); |
| assertFalse(serverCallback.verifyCertificateChainCalled); |
| assertFalse(clientCallback.clientCertificateRequestedCalled); |
| assertFalse(serverCallback.clientCertificateRequestedCalled); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| assertTrue(clientCallback.clientPSKKeyRequestedInvoked); |
| assertFalse(clientCallback.serverPSKKeyRequestedInvoked); |
| assertFalse(serverCallback.clientPSKKeyRequestedInvoked); |
| assertTrue(serverCallback.serverPSKKeyRequestedInvoked); |
| assertContains(cHooks.negotiatedCipherSuite, "PSK"); |
| assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite); |
| assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint); |
| assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint); |
| assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_psk_key_mismatch() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = "1, 2, 3, 3, Testing...".getBytes("UTF-8"); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_psk_with_no_client_key() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = null; |
| sHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_psk_with_no_server_key() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks(); |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = null; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test |
| @SuppressWarnings("deprecation") |
| public void test_SSL_do_handshake_with_psk_key_too_long() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| ClientHooks cHooks = new ClientHooks() { |
| @Override |
| public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) { |
| super.configureCallbacks(callbacks); |
| callbacks.clientPSKKeyRequestedResult = PSKKeyManager.MAX_KEY_LENGTH_BYTES + 1; |
| } |
| }; |
| ServerHooks sHooks = new ServerHooks(); |
| cHooks.pskEnabled = true; |
| sHooks.pskEnabled = true; |
| cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8"); |
| sHooks.pskKey = cHooks.pskKey; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_ocsp_response() throws Exception { |
| final byte[] OCSP_TEST_DATA = new byte[] {1, 2, 3, 4}; |
| |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_enable_ocsp_stapling(s, null); |
| return s; |
| } |
| |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| assertEqualByteArrays(OCSP_TEST_DATA, NativeCrypto.SSL_get_ocsp_response(ssl, null)); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_ocsp_response(s, null, OCSP_TEST_DATA); |
| return s; |
| } |
| }; |
| |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| } |
| |
| @Test |
| public void test_SSL_do_handshake_with_sct_extension() throws Exception { |
| // Fake SCT extension has a length of overall extension (unsigned 16-bit). |
| // Each SCT entry has a length (unsigned 16-bit) and data. |
| final byte[] SCT_TEST_DATA = new byte[] {0, 6, 0, 4, 1, 2, 3, 4}; |
| |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_enable_signed_cert_timestamps(s, null); |
| return s; |
| } |
| |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| assertEqualByteArrays( |
| SCT_TEST_DATA, NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl, null)); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_signed_cert_timestamp_list(s, null, SCT_TEST_DATA); |
| return s; |
| } |
| }; |
| |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| |
| assertTrue(clientCallback.onNewSessionEstablishedInvoked); |
| assertTrue(serverCallback.onNewSessionEstablishedInvoked); |
| assertTrue(clientCallback.handshakeCompletedCalled); |
| assertTrue(serverCallback.handshakeCompletedCalled); |
| } |
| |
| @Test |
| @SuppressWarnings("deprecation") |
| public void test_SSL_use_psk_identity_hint() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_use_psk_identity_hint(s, null, null); |
| NativeCrypto.SSL_use_psk_identity_hint(s, null, "test"); |
| |
| try { |
| // 800 characters is much longer than the permitted maximum. |
| StringBuilder pskIdentityHint = new StringBuilder(); |
| for (int i = 0; i < 160; i++) { |
| pskIdentityHint.append(" long"); |
| } |
| assertTrue(pskIdentityHint.length() > PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES); |
| NativeCrypto.SSL_use_psk_identity_hint(s, null, pskIdentityHint.toString()); |
| fail(); |
| } catch (SSLException expected) { |
| // Expected. |
| } |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_session_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_session(NULL, null, NULL); |
| } |
| |
| @Test |
| public void test_SSL_set_session() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_set_session(s, null, NULL); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| |
| { |
| final long clientContext = NativeCrypto.SSL_CTX_new(); |
| final long serverContext = NativeCrypto.SSL_CTX_new(); |
| final ServerSocket listener = newServerSocket(); |
| final long[] clientSession = new long[] {NULL}; |
| final long[] serverSession = new long[] {NULL}; |
| { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long getContext() throws SSLException { |
| return clientContext; |
| } |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| super.afterHandshake(NULL, s, NULL, sock, fd, callback); |
| clientSession[0] = session; |
| } |
| }; |
| Hooks sHooks = new ServerHooks( |
| getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long getContext() throws SSLException { |
| return serverContext; |
| } |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| super.afterHandshake(NULL, s, NULL, sock, fd, callback); |
| serverSession[0] = session; |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| assertEqualSessions(clientSession[0], serverSession[0]); |
| { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long getContext() throws SSLException { |
| return clientContext; |
| } |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = NativeCrypto.SSL_new(clientContext, null); |
| NativeCrypto.SSL_set_session(s, null, clientSession[0]); |
| return s; |
| } |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| assertEqualSessions(clientSession[0], session); |
| super.afterHandshake(NULL, s, NULL, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks( |
| getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long getContext() throws SSLException { |
| return serverContext; |
| } |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| assertEqualSessions(serverSession[0], session); |
| super.afterHandshake(NULL, s, NULL, sock, fd, callback); |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| NativeCrypto.SSL_SESSION_free(clientSession[0]); |
| NativeCrypto.SSL_SESSION_free(serverSession[0]); |
| NativeCrypto.SSL_CTX_free(serverContext, null); |
| NativeCrypto.SSL_CTX_free(clientContext, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_session_creation_enabled_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_session_creation_enabled(NULL, null, false); |
| } |
| |
| @Test |
| public void test_SSL_set_session_creation_enabled() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_set_session_creation_enabled(s, null, false); |
| NativeCrypto.SSL_set_session_creation_enabled(s, null, true); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| |
| final ServerSocket listener = newServerSocket(); |
| |
| // negative test case for SSL_set_session_creation_enabled(false) on client |
| { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_session_creation_enabled(s, null, false); |
| return s; |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| @SuppressWarnings("unused") |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| try { |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| // negative test case for SSL_set_session_creation_enabled(false) on server |
| { |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_session_creation_enabled(s, null, false); |
| return s; |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| @SuppressWarnings("unused") |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| try { |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLHandshakeException.class, expected.getCause().getClass()); |
| } |
| try { |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SSLProtocolException.class, expected.getCause().getClass()); |
| } |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_tlsext_host_name_withNullSslShouldThrow() throws Exception { |
| NativeCrypto.SSL_set_tlsext_host_name(NULL, null, null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_set_tlsext_host_name_withNullHostnameShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| try { |
| NativeCrypto.SSL_set_tlsext_host_name(s, null, null); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = SSLException.class) |
| public void SSL_set_tlsext_host_name_withTooLongHostnameShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| try { |
| char[] longHostname = new char[256]; |
| Arrays.fill(longHostname, 'w'); |
| NativeCrypto.SSL_set_tlsext_host_name(s, null, new String(longHostname)); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_set_tlsext_host_name() throws Exception { |
| final String hostname = "www.android.com"; |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| |
| assertNull(NativeCrypto.SSL_get_servername(s, null)); |
| NativeCrypto.SSL_set_tlsext_host_name(s, null, hostname); |
| assertEquals(hostname, NativeCrypto.SSL_get_servername(s, null)); |
| |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| |
| final ServerSocket listener = newServerSocket(); |
| |
| // normal |
| Hooks cHooks = new Hooks() { |
| @Override |
| public long beforeHandshake(long c) throws SSLException { |
| long s = super.beforeHandshake(c); |
| NativeCrypto.SSL_set_tlsext_host_name(s, null, hostname); |
| return s; |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| assertEquals(hostname, NativeCrypto.SSL_get_servername(s, null)); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test |
| public void alpnWithProtocolListShouldSucceed() throws Exception { |
| final byte[] clientAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"}); |
| final byte[] serverAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"spdy/2", "foo", "bar"}); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertEquals("spdy/2", new String(negotiated, "UTF-8")); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long ssl, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertEquals("spdy/2", new String(negotiated, "UTF-8")); |
| super.afterHandshake(session, ssl, c, sock, fd, callback); |
| } |
| }; |
| |
| ServerSocket listener = newServerSocket(); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, clientAlpnProtocols, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, serverAlpnProtocols, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test |
| public void alpnWithProtocolListShouldFail() throws Exception { |
| final byte[] clientAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"}); |
| final byte[] serverAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"h2", "bar", "baz"}); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertNull(negotiated); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long ssl, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertNull(negotiated); |
| super.afterHandshake(session, ssl, c, sock, fd, callback); |
| } |
| }; |
| |
| ServerSocket listener = newServerSocket(); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, clientAlpnProtocols, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, serverAlpnProtocols, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test |
| public void alpnWithServerProtocolSelectorShouldSucceed() throws Exception { |
| final byte[] clientAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"}); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertEquals("spdy/2", new String(negotiated, "UTF-8")); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long ssl, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertEquals("spdy/2", new String(negotiated, "UTF-8")); |
| super.afterHandshake(session, ssl, c, sock, fd, callback); |
| } |
| }; |
| |
| ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class); |
| SSLEngine engine = Mockito.mock(SSLEngine.class); |
| ApplicationProtocolSelectorAdapter adapter = new ApplicationProtocolSelectorAdapter(engine, selector); |
| when(selector.selectApplicationProtocol(same(engine), Matchers.anyListOf(String.class))) |
| .thenReturn("spdy/2"); |
| |
| ServerSocket listener = newServerSocket(); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, clientAlpnProtocols, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, adapter); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test |
| public void alpnWithServerProtocolSelectorShouldFail() throws Exception { |
| final byte[] clientAlpnProtocols = |
| SSLUtils.encodeProtocols(new String[] {"http/1.1", "foo", "spdy/2"}); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long ssl, long context, Socket socket, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertNull(negotiated); |
| super.afterHandshake(session, ssl, context, socket, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long ssl, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] negotiated = NativeCrypto.getApplicationProtocol(ssl, null); |
| assertNull(negotiated); |
| super.afterHandshake(session, ssl, c, sock, fd, callback); |
| } |
| }; |
| |
| ApplicationProtocolSelector selector = Mockito.mock(ApplicationProtocolSelector.class); |
| SSLEngine engine = Mockito.mock(SSLEngine.class); |
| ApplicationProtocolSelectorAdapter adapter = new ApplicationProtocolSelectorAdapter(engine, selector); |
| when(selector.selectApplicationProtocol(same(engine), Matchers.anyListOf(String.class))) |
| .thenReturn("h2"); |
| |
| ServerSocket listener = newServerSocket(); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, clientAlpnProtocols, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, adapter); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_SSL_get_servername_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_get_servername(NULL, null); |
| } |
| |
| @Test |
| public void SSL_get_servername_shouldReturnNull() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| assertNull(NativeCrypto.SSL_get_servername(s, null)); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| |
| // additional positive testing by test_SSL_set_tlsext_host_name |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_get0_peer_certificates_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_get0_peer_certificates(NULL, null); |
| } |
| |
| @Test |
| public void test_SSL_get0_peer_certificates() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| byte[][] cc = NativeCrypto.SSL_get0_peer_certificates(s, null); |
| assertEqualByteArrays(getEncodedServerCertificates(), cc); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test |
| public void test_SSL_cipher_names() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| Hooks cHooks = new Hooks(); |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| // Both legacy and standard names are accepted. |
| cHooks.enabledCipherSuites = Collections.singletonList("ECDHE-RSA-AES128-GCM-SHA256"); |
| sHooks.enabledCipherSuites = |
| Collections.singletonList("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| // The standard name is always reported. |
| assertEquals("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", cHooks.negotiatedCipherSuite); |
| assertEquals("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", sHooks.negotiatedCipherSuite); |
| } |
| |
| private final byte[] BYTES = new byte[] {2, -3, 5, 127, 0, -128}; |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_read_withNullSslShouldThrow() throws Exception { |
| NativeCrypto.SSL_read(NULL, null, null, null, null, 0, 0, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_read_withNullFdShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_read(s, null, null, DUMMY_CB, null, 0, 0, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_read_withNullCallbacksShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_read(s, null, INVALID_FD, null, null, 0, 0, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_read_withNullBytesShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_read(s, null, INVALID_FD, DUMMY_CB, null, 0, 0, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = SSLException.class) |
| public void SSL_read_beforeHandshakeShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_read(s, null, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void test_SSL_read() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| // normal case |
| { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| byte[] in = new byte[256]; |
| assertEquals(BYTES.length, |
| NativeCrypto.SSL_read(s, null, fd, callback, in, 0, BYTES.length, 0)); |
| for (int i = 0; i < BYTES.length; i++) { |
| assertEquals(BYTES[i], in[i]); |
| } |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| NativeCrypto.SSL_write(s, null, fd, callback, BYTES, 0, BYTES.length, 0); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| // timeout case |
| try { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 1); |
| fail(); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| @SuppressWarnings("unused") |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| fail(); |
| } catch (ExecutionException expected) { |
| assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_write_withNullSslShouldThrow() throws Exception { |
| NativeCrypto.SSL_write(NULL, null, null, null, null, 0, 0, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_write_withNullFdShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_write(s, null, null, DUMMY_CB, null, 0, 1, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_write_withNullCallbacksShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_write(s, null, INVALID_FD, null, null, 0, 1, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_write_withNullBytesShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_write(s, null, INVALID_FD, DUMMY_CB, null, 0, 1, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test(expected = SSLException.class) |
| public void SSL_write_beforeHandshakeShouldThrow() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| NativeCrypto.SSL_write(s, null, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void SSL_interrupt_withNullShouldSucceed() { |
| // SSL_interrupt is a rare case that tolerates a null SSL argument |
| NativeCrypto.SSL_interrupt(NULL, null); |
| } |
| |
| @Test |
| public void SSL_interrupt_withoutHandshakeShouldSucceed() throws Exception { |
| // also works without handshaking |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| NativeCrypto.SSL_interrupt(s, null); |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| |
| @Test |
| public void test_SSL_interrupt() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()) { |
| @Override |
| public void afterHandshake(long session, final long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| new Thread() { |
| @Override |
| public void run() { |
| try { |
| Thread.sleep(1000); |
| NativeCrypto.SSL_interrupt(s, null); |
| } catch (Exception e) { |
| // Expected. |
| } |
| } |
| }.start(); |
| assertEquals(-1, NativeCrypto.SSL_read(s, null, fd, callback, new byte[1], 0, 1, 0)); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| private static abstract class SSLSessionWrappedTask { |
| public abstract void run(long sslSession) throws Exception; |
| } |
| |
| private void wrapWithSSLSession(SSLSessionWrappedTask task) throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| long s = NativeCrypto.SSL_new(c, null); |
| try { |
| task.run(s); |
| } finally { |
| NativeCrypto.SSL_free(s, null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| } |
| } |
| |
| @Test |
| public void SSL_shutdown_withNullFdShouldSucceed() throws Exception { |
| // We tolerate a null FileDescriptor |
| wrapWithSSLSession(new SSLSessionWrappedTask() { |
| @Override |
| public void run(long sslSession) throws Exception { |
| NativeCrypto.SSL_shutdown(sslSession, null, null, DUMMY_CB); |
| } |
| }); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_shutdown_withNullCallbacksShouldThrow() throws Exception { |
| wrapWithSSLSession(new SSLSessionWrappedTask() { |
| @Override |
| public void run(long sslSession) throws Exception { |
| NativeCrypto.SSL_shutdown(sslSession, null, INVALID_FD, null); |
| } |
| }); |
| } |
| |
| @Test |
| public void SSL_shutdown_withNullSslShouldSucceed() throws Exception { |
| // SSL_shutdown is a rare case that tolerates a null SSL argument |
| NativeCrypto.SSL_shutdown(NULL, null, INVALID_FD, DUMMY_CB); |
| } |
| |
| @Test(expected = SocketException.class) |
| public void SSL_shutdown_beforeHandshakeShouldThrow() throws Exception { |
| // handshaking not yet performed |
| wrapWithSSLSession(new SSLSessionWrappedTask() { |
| @Override |
| public void run(long sslSession) throws Exception { |
| NativeCrypto.SSL_shutdown(sslSession, null, INVALID_FD, DUMMY_CB); |
| } |
| }); |
| |
| // positively tested elsewhere because handshake uses use |
| // SSL_shutdown to ensure SSL_SESSIONs are reused. |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_free_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_free(NULL, null); |
| } |
| |
| @Test |
| public void test_SSL_free() throws Exception { |
| long c = NativeCrypto.SSL_CTX_new(); |
| NativeCrypto.SSL_free(NativeCrypto.SSL_new(c, null), null); |
| NativeCrypto.SSL_CTX_free(c, null); |
| |
| // additional positive testing elsewhere because handshake |
| // uses use SSL_free to cleanup in afterHandshake. |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_SESSION_session_id_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_SESSION_session_id(NULL); |
| } |
| |
| @Test |
| public void test_SSL_SESSION_session_id() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| byte[] id = NativeCrypto.SSL_SESSION_session_id(session); |
| assertNotNull(id); |
| assertEquals(32, id.length); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_SESSION_get_time_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_SESSION_get_time(NULL); |
| } |
| |
| @Test |
| public void test_SSL_SESSION_get_time() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| { |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, |
| FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { |
| long time = NativeCrypto.SSL_SESSION_get_time(session); |
| assertTrue(time != 0); |
| assertTrue(time < System.currentTimeMillis()); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = |
| handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_SESSION_get_version_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_SESSION_get_version(NULL); |
| } |
| |
| @Test |
| public void test_SSL_SESSION_get_version() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| String v = NativeCrypto.SSL_SESSION_get_version(session); |
| assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(v)); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void SSL_SESSION_cipher_withNullShouldThrow() throws Exception { |
| NativeCrypto.SSL_SESSION_cipher(NULL); |
| } |
| |
| @Test |
| public void test_SSL_SESSION_cipher() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| String nativeCipher = NativeCrypto.SSL_SESSION_cipher(session); |
| String javaCipher = NativeCrypto.cipherSuiteFromJava(nativeCipher); |
| assertTrue(NativeCrypto.SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.contains(javaCipher)); |
| // SSL_SESSION_cipher should return a standard name rather than an OpenSSL name. |
| assertTrue(nativeCipher.startsWith("TLS_")); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| /* |
| * Additional positive testing elsewhere because handshake |
| * uses use SSL_SESSION_free to cleanup in afterHandshake. |
| */ |
| @Test(expected = NullPointerException.class) |
| public void SSL_SESSION_free_NullArgument() throws Exception { |
| NativeCrypto.SSL_SESSION_free(NULL); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void i2d_SSL_Session_WithNullSessionShouldThrow() throws Exception { |
| NativeCrypto.i2d_SSL_SESSION(NULL); |
| } |
| |
| @Test |
| public void test_i2d_SSL_SESSION() throws Exception { |
| final ServerSocket listener = newServerSocket(); |
| |
| Hooks cHooks = new Hooks() { |
| @Override |
| public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, |
| SSLHandshakeCallbacks callback) throws Exception { |
| byte[] b = NativeCrypto.i2d_SSL_SESSION(session); |
| assertNotNull(b); |
| long session2 = NativeCrypto.d2i_SSL_SESSION(b); |
| assertTrue(session2 != NULL); |
| |
| // Make sure d2i_SSL_SESSION retores SSL_SESSION_cipher value http://b/7091840 |
| assertTrue(NativeCrypto.SSL_SESSION_cipher(session2) != null); |
| assertEquals(NativeCrypto.SSL_SESSION_cipher(session), |
| NativeCrypto.SSL_SESSION_cipher(session2)); |
| |
| NativeCrypto.SSL_SESSION_free(session2); |
| super.afterHandshake(session, s, c, sock, fd, callback); |
| } |
| }; |
| Hooks sHooks = new ServerHooks(getServerPrivateKey(), getEncodedServerCertificates()); |
| Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); |
| Future<TestSSLHandshakeCallbacks> server = |
| handshake(listener, 0, false, sHooks, null, null); |
| client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void d2i_SSL_SESSION_NullArgument() throws Exception { |
| NativeCrypto.d2i_SSL_SESSION(null); |
| } |
| |
| @Test(expected = IOException.class) |
| public void d2i_SSL_SESSION_EmptyArgument() throws Exception { |
| NativeCrypto.d2i_SSL_SESSION(new byte[0]); |
| } |
| |
| @Test(expected = IOException.class) |
| public void d2i_SSL_SESSION_InvalidArgument() throws Exception { |
| NativeCrypto.d2i_SSL_SESSION(new byte[1]); |
| } |
| |
| @Test |
| public void test_X509_NAME_hashes() { |
| // ensure these hash functions are stable over time since the |
| // /system/etc/security/cacerts CA filenames have to be |
| // consistent with the output. |
| X500Principal name = new X500Principal("CN=localhost"); |
| assertEquals(-1372642656, NativeCrypto.X509_NAME_hash(name)); // SHA1 |
| assertEquals(-1626170662, NativeCrypto.X509_NAME_hash_old(name)); // MD5 |
| } |
| |
| @Test |
| public void test_RAND_bytes_Success() throws Exception { |
| byte[] output = new byte[128]; |
| NativeCrypto.RAND_bytes(output); |
| |
| boolean isZero = true; |
| for (byte anOutput : output) { |
| isZero &= (anOutput == 0); |
| } |
| |
| assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) " |
| + "and probably indicates an error.", |
| isZero); |
| } |
| |
| @Test(expected = RuntimeException.class) |
| public void RAND_bytes_withNullShouldThrow() throws Exception { |
| NativeCrypto.RAND_bytes(null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_EVP_get_digestbyname_NullArgument() throws Exception { |
| NativeCrypto.EVP_get_digestbyname(null); |
| } |
| |
| @Test(expected = RuntimeException.class) |
| public void EVP_get_digestbyname_withEmptyShouldThrow() throws Exception { |
| NativeCrypto.EVP_get_digestbyname(""); |
| } |
| |
| @Test(expected = RuntimeException.class) |
| public void EVP_get_digestbyname_withInvalidDigestShouldThrow() throws Exception { |
| NativeCrypto.EVP_get_digestbyname("foobar"); |
| } |
| |
| @Test |
| public void test_EVP_get_digestbyname() throws Exception { |
| assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL); |
| } |
| |
| @Test |
| public void test_EVP_DigestSignInit() throws Exception { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); |
| kpg.initialize(512); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| RSAPrivateCrtKey privKey = (RSAPrivateCrtKey) kp.getPrivate(); |
| |
| NativeRef.EVP_PKEY pkey; |
| pkey = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA( |
| privKey.getModulus().toByteArray(), privKey.getPublicExponent().toByteArray(), |
| privKey.getPrivateExponent().toByteArray(), privKey.getPrimeP().toByteArray(), |
| privKey.getPrimeQ().toByteArray(), privKey.getPrimeExponentP().toByteArray(), |
| privKey.getPrimeExponentQ().toByteArray(), |
| privKey.getCrtCoefficient().toByteArray())); |
| assertNotNull(pkey); |
| |
| final NativeRef.EVP_MD_CTX ctx = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create()); |
| long evpMd = NativeCrypto.EVP_get_digestbyname("sha256"); |
| NativeCrypto.EVP_DigestSignInit(ctx, evpMd, pkey); |
| |
| try { |
| NativeCrypto.EVP_DigestSignInit(ctx, 0, pkey); |
| fail(); |
| } catch (RuntimeException expected) { |
| // Expected. |
| } |
| |
| try { |
| NativeCrypto.EVP_DigestSignInit(ctx, evpMd, null); |
| fail(); |
| } catch (RuntimeException expected) { |
| // Expected. |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void get_RSA_private_params_NullArgument() throws Exception { |
| NativeCrypto.get_RSA_private_params(null); |
| } |
| |
| @Test(expected = RuntimeException.class) |
| public void test_get_RSA_private_params() throws Exception { |
| // Test getting params for the wrong kind of key. |
| final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); |
| assertFalse(groupCtx == NULL); |
| NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx); |
| NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group)); |
| NativeCrypto.get_RSA_private_params(ctx); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void get_RSA_public_params_NullArgument() throws Exception { |
| NativeCrypto.get_RSA_public_params(null); |
| } |
| |
| @Test(expected = RuntimeException.class) |
| public void test_get_RSA_public_params() throws Exception { |
| // Test getting params for the wrong kind of key. |
| final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); |
| assertFalse(groupCtx == NULL); |
| NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx); |
| NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group)); |
| NativeCrypto.get_RSA_public_params(ctx); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void RSA_size_NullArgumentFailure() throws Exception { |
| NativeCrypto.RSA_size(null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void RSA_private_encrypt_NullArgumentFailure() throws Exception { |
| NativeCrypto.RSA_private_encrypt(0, new byte[0], new byte[0], null, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void RSA_private_decrypt_NullArgumentFailure() throws Exception { |
| NativeCrypto.RSA_private_decrypt(0, new byte[0], new byte[0], null, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_RSA_public_encrypt_NullArgumentFailure() throws Exception { |
| NativeCrypto.RSA_public_encrypt(0, new byte[0], new byte[0], null, 0); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_RSA_public_decrypt_NullArgumentFailure() throws Exception { |
| NativeCrypto.RSA_public_decrypt(0, new byte[0], new byte[0], null, 0); |
| } |
| |
| /* |
| * Test vector generation: |
| * openssl rand -hex 16 |
| */ |
| private static final byte[] AES_128_KEY = new byte[] { |
| (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2, |
| (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29, |
| (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f, |
| }; |
| |
| @Test |
| public void testEC_GROUP() throws Exception { |
| /* Test using NIST's P-256 curve */ |
| check_EC_GROUP("prime256v1", |
| "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", |
| "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", |
| "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", |
| "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", |
| "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", |
| "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1L); |
| } |
| |
| private void check_EC_GROUP(String name, String pStr, String aStr, String bStr, String xStr, |
| String yStr, String nStr, long hLong) throws Exception { |
| long groupRef = NativeCrypto.EC_GROUP_new_by_curve_name(name); |
| assertFalse(groupRef == NULL); |
| NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupRef); |
| |
| // prime |
| BigInteger p = new BigInteger(pStr, 16); |
| // first coefficient |
| BigInteger a = new BigInteger(aStr, 16); |
| // second coefficient |
| BigInteger b = new BigInteger(bStr, 16); |
| // x affine coordinate of generator |
| BigInteger x = new BigInteger(xStr, 16); |
| // y affine coordinate of generator |
| BigInteger y = new BigInteger(yStr, 16); |
| // order of the generator |
| BigInteger n = new BigInteger(nStr, 16); |
| // cofactor of generator |
| BigInteger h = BigInteger.valueOf(hLong); |
| |
| byte[][] pab = NativeCrypto.EC_GROUP_get_curve(group); |
| assertEquals(3, pab.length); |
| |
| BigInteger p2 = new BigInteger(pab[0]); |
| assertEquals(p, p2); |
| |
| BigInteger a2 = new BigInteger(pab[1]); |
| assertEquals(a, a2); |
| |
| BigInteger b2 = new BigInteger(pab[2]); |
| assertEquals(b, b2); |
| |
| NativeRef.EC_POINT point = |
| new NativeRef.EC_POINT(NativeCrypto.EC_GROUP_get_generator(group)); |
| |
| byte[][] xy = NativeCrypto.EC_POINT_get_affine_coordinates(group, point); |
| assertEquals(2, xy.length); |
| |
| BigInteger x2 = new BigInteger(xy[0]); |
| assertEquals(x, x2); |
| |
| BigInteger y2 = new BigInteger(xy[1]); |
| assertEquals(y, y2); |
| |
| BigInteger n2 = new BigInteger(NativeCrypto.EC_GROUP_get_order(group)); |
| assertEquals(n, n2); |
| |
| BigInteger h2 = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(group)); |
| assertEquals(h, h2); |
| |
| NativeRef.EVP_PKEY key1 = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group)); |
| NativeRef.EC_GROUP groupTmp = new NativeRef.EC_GROUP(NativeCrypto.EC_KEY_get1_group(key1)); |
| assertEquals(NativeCrypto.EC_GROUP_get_curve_name(group), |
| NativeCrypto.EC_GROUP_get_curve_name(groupTmp)); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_EC_KEY_get_private_key_NullArgumentFailure() throws Exception { |
| NativeCrypto.EC_KEY_get_private_key(null); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void test_EC_KEY_get_public_key_NullArgumentFailure() throws Exception { |
| NativeCrypto.EC_KEY_get_public_key(null); |
| } |
| |
| @Test |
| public void test_ECKeyPairGenerator_CurvesAreValid() throws Exception { |
| OpenSSLECKeyPairGenerator.assertCurvesAreValid(); |
| } |
| |
| @Test |
| public void test_ECDH_compute_key_null_key_Failure() throws Exception { |
| final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); |
| assertFalse(groupCtx == NULL); |
| NativeRef.EC_GROUP groupRef = new NativeRef.EC_GROUP(groupCtx); |
| NativeRef.EVP_PKEY pkey1Ref = |
| new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(groupRef)); |
| NativeRef.EVP_PKEY pkey2Ref = |
| new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(groupRef)); |
| |
| byte[] out = new byte[128]; |
| int outOffset = 0; |
| // Assert that the method under test works fine with the two |
| // non-null keys |
| NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, pkey2Ref); |
| |
| // Assert that it fails when only the first key is null |
| try { |
| NativeCrypto.ECDH_compute_key(out, outOffset, null, pkey2Ref); |
| fail(); |
| } catch (NullPointerException expected) { |
| // Expected. |
| } |
| |
| // Assert that it fails when only the second key is null |
| try { |
| NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, null); |
| fail(); |
| } catch (NullPointerException expected) { |
| // Expected. |
| } |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_CipherInit_ex_withNullCtxShouldThrow() throws Exception { |
| final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); |
| NativeCrypto.EVP_CipherInit_ex(null, evpCipher, null, null, true); |
| } |
| |
| @Test |
| public void test_EVP_CipherInit_ex_Null_Failure() throws Exception { |
| final NativeRef.EVP_CIPHER_CTX ctx = |
| new NativeRef.EVP_CIPHER_CTX(NativeCrypto.EVP_CIPHER_CTX_new()); |
| final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); |
| |
| /* Initialize encrypting. */ |
| NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, true); |
| NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, true); |
| |
| /* Initialize decrypting. */ |
| NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, false); |
| NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, false); |
| } |
| |
| @Test |
| public void test_EVP_CipherInit_ex_Success() throws Exception { |
| final NativeRef.EVP_CIPHER_CTX ctx = |
| new NativeRef.EVP_CIPHER_CTX(NativeCrypto.EVP_CIPHER_CTX_new()); |
| final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); |
| NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, AES_128_KEY, null, true); |
| } |
| |
| @Test |
| public void test_EVP_CIPHER_iv_length() throws Exception { |
| long aes128ecb = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); |
| assertEquals(0, NativeCrypto.EVP_CIPHER_iv_length(aes128ecb)); |
| |
| long aes128cbc = NativeCrypto.EVP_get_cipherbyname("aes-128-cbc"); |
| assertEquals(16, NativeCrypto.EVP_CIPHER_iv_length(aes128cbc)); |
| } |
| |
| @Test |
| public void test_OpenSSLKey_toJava() throws Exception { |
| OpenSSLKey key1; |
| |
| BigInteger e = BigInteger.valueOf(65537); |
| key1 = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(1024, e.toByteArray())); |
| assertTrue(key1.getPublicKey() instanceof RSAPublicKey); |
| |
| final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); |
| assertFalse(groupCtx == NULL); |
| NativeRef.EC_GROUP group1 = new NativeRef.EC_GROUP(groupCtx); |
| key1 = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group1)); |
| assertTrue(key1.getPublicKey() instanceof ECPublicKey); |
| } |
| |
| @Test |
| public void test_create_BIO_InputStream() throws Exception { |
| byte[] actual = "Test".getBytes("UTF-8"); |
| ByteArrayInputStream is = new ByteArrayInputStream(actual); |
| |
| @SuppressWarnings("resource") |
| OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true); |
| try { |
| byte[] buffer = new byte[1024]; |
| int numRead = NativeCrypto.BIO_read(bis.getBioContext(), buffer); |
| assertEquals(actual.length, numRead); |
| assertEquals(Arrays.toString(actual), |
| Arrays.toString(Arrays.copyOfRange(buffer, 0, numRead))); |
| } finally { |
| bis.release(); |
| } |
| } |
| |
| @Test |
| public void test_create_BIO_OutputStream() throws Exception { |
| byte[] actual = "Test".getBytes("UTF-8"); |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| |
| long ctx = NativeCrypto.create_BIO_OutputStream(os); |
| try { |
| NativeCrypto.BIO_write(ctx, actual, 0, actual.length); |
| assertEquals(actual.length, os.size()); |
| assertEquals(Arrays.toString(actual), Arrays.toString(os.toByteArray())); |
| } finally { |
| NativeCrypto.BIO_free_all(ctx); |
| } |
| } |
| |
| @Test |
| public void test_get_ocsp_single_extension() throws Exception { |
| final String OCSP_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.5"; |
| |
| byte[] ocspResponse = readTestFile("ocsp-response.der"); |
| byte[] expected = readTestFile("ocsp-response-sct-extension.der"); |
| OpenSSLX509Certificate certificate = |
| OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert-ct-poisoned.pem")); |
| OpenSSLX509Certificate issuer = |
| OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem")); |
| |
| byte[] extension = NativeCrypto.get_ocsp_single_extension( |
| ocspResponse, OCSP_SCT_LIST_OID, certificate.getContext(), certificate, issuer.getContext(), issuer); |
| |
| assertEqualByteArrays(expected, extension); |
| } |
| |
| private static long getRawPkeyCtxForEncrypt() throws Exception { |
| return NativeCrypto.EVP_PKEY_encrypt_init(getRsaPkey(generateRsaKey())); |
| } |
| |
| private static NativeRef.EVP_PKEY_CTX getPkeyCtxForEncrypt() throws Exception { |
| return new NativeRef.EVP_PKEY_CTX(getRawPkeyCtxForEncrypt()); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_encrypt_NullKeyArgument() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt(null, new byte[128], 0, new byte[128], 0, 128); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_encrypt_NullOutputArgument() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt(getPkeyCtxForEncrypt(), null, 0, new byte[128], 0, 128); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_encrypt_NullInputArgument() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt(getPkeyCtxForEncrypt(), new byte[128], 0, null, 0, 128); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_OutputIndexOOBUnder() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], -1, new byte[128], 0, 128); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_OutputIndexOOBOver() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], 129, new byte[128], 0, 128); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_InputIndexOOBUnder() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], -1, 128); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_InputIndexOOBOver() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 128, 128); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_InputLengthNegative() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 0, -1); |
| } |
| |
| @Test(expected = ArrayIndexOutOfBoundsException.class) |
| public void EVP_PKEY_encrypt_InputIndexLengthOOB() throws Exception { |
| NativeCrypto.EVP_PKEY_encrypt( |
| getPkeyCtxForEncrypt(), new byte[128], 0, new byte[128], 100, 29); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_CTX_set_rsa_mgf1_md_NullPkeyCtx() throws Exception { |
| NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(NULL, EvpMdRef.SHA256.EVP_MD); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_CTX_set_rsa_mgf1_md_NullMdCtx() throws Exception { |
| long pkeyCtx = getRawPkeyCtxForEncrypt(); |
| NativeRef.EVP_PKEY_CTX holder = new NativeRef.EVP_PKEY_CTX(pkeyCtx); |
| NativeCrypto.EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, NULL); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_CTX_set_rsa_oaep_md_NullPkeyCtx() throws Exception { |
| NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(NULL, EvpMdRef.SHA256.EVP_MD); |
| } |
| |
| @Test(expected = NullPointerException.class) |
| public void EVP_PKEY_CTX_set_rsa_oaep_md_NullMdCtx() throws Exception { |
| long pkeyCtx = getRawPkeyCtxForEncrypt(); |
| new NativeRef.EVP_PKEY_CTX(pkeyCtx); |
| NativeCrypto.EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, NULL); |
| } |
| |
| @Test(expected = ParsingException.class) |
| public void d2i_X509_InvalidFailure() throws Exception { |
| NativeCrypto.d2i_X509(new byte[1]); |
| } |
| |
| private static void assertContains(String actualValue, String expectedSubstring) { |
| if (actualValue == null) { |
| return; |
| } |
| if (actualValue.contains(expectedSubstring)) { |
| return; |
| } |
| fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\""); |
| } |
| |
| private static ServerSocket newServerSocket() throws IOException { |
| return new ServerSocket(0, 50, TestUtils.getLoopbackAddress()); |
| } |
| } |