/* * 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 org.conscrypt; import dalvik.system.BaseDexClassLoader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; import java.io.IOException; import java.io.UnsupportedEncodingException; 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.DSAPublicKey; 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.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.SSLException; import javax.net.ssl.SSLProtocolException; import javax.security.auth.x500.X500Principal; import junit.framework.TestCase; import libcore.io.IoUtils; import libcore.java.security.StandardNames; import libcore.java.security.TestKeyStore; import org.conscrypt.NativeCrypto.SSLHandshakeCallbacks; import static org.conscrypt.NativeCrypto.SSL_MODE_CBC_RECORD_SPLITTING; import static org.conscrypt.NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH; public class NativeCryptoTest extends TestCase { /** Corresponds to the native test library "libjavacoretests.so" */ public static final String TEST_ENGINE_ID = "javacoretests"; 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_CERTIFICATES; private static OpenSSLKey CLIENT_PRIVATE_KEY; private static OpenSSLX509Certificate[] CLIENT_CERTIFICATES_HOLDER; private static long[] CLIENT_CERTIFICATES; private static byte[][] CA_PRINCIPALS; private static OpenSSLKey CHANNEL_ID_PRIVATE_KEY; private static byte[] CHANNEL_ID; @Override protected void tearDown() throws Exception { assertEquals(0, NativeCrypto.ERR_peek_last_error()); } private static OpenSSLKey getServerPrivateKey() { initCerts(); return SERVER_PRIVATE_KEY; } private static long[] getServerCertificates() { initCerts(); return SERVER_CERTIFICATES; } private static OpenSSLKey getClientPrivateKey() { initCerts(); return CLIENT_PRIVATE_KEY; } private static long[] getClientCertificates() { initCerts(); return 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_CERTIFICATES = getCertificateReferences(SERVER_CERTIFICATES_HOLDER); PrivateKeyEntry clientPrivateKeyEntry = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA"); CLIENT_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(clientPrivateKeyEntry.getPrivateKey()); CLIENT_CERTIFICATES_HOLDER = encodeCertificateList( clientPrivateKeyEntry.getCertificateChain()); CLIENT_CERTIFICATES = getCertificateReferences(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 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(); } 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], actual[i]); } } public static void assertEqualByteArrays(byte[][] expected, byte[][] actual) { assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual)); } public void test_EVP_PKEY_cmp() throws Exception { try { NativeCrypto.EVP_PKEY_cmp(NULL, NULL); fail("Should throw NullPointerException when arguments are NULL"); } catch (NullPointerException expected) { } KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair kp1 = kpg.generateKeyPair(); RSAPrivateCrtKey privKey1 = (RSAPrivateCrtKey) kp1.getPrivate(); KeyPair kp2 = kpg.generateKeyPair(); RSAPrivateCrtKey privKey2 = (RSAPrivateCrtKey) kp2.getPrivate(); long pkey1 = 0, pkey1_copy = 0, pkey2 = 0; try { pkey1 = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(), privKey1.getPublicExponent().toByteArray(), privKey1.getPrivateExponent().toByteArray(), privKey1.getPrimeP().toByteArray(), privKey1.getPrimeQ().toByteArray(), privKey1.getPrimeExponentP().toByteArray(), privKey1.getPrimeExponentQ().toByteArray(), privKey1.getCrtCoefficient().toByteArray()); assertNotSame(NULL, pkey1); pkey1_copy = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(), privKey1.getPublicExponent().toByteArray(), privKey1.getPrivateExponent().toByteArray(), privKey1.getPrimeP().toByteArray(), privKey1.getPrimeQ().toByteArray(), privKey1.getPrimeExponentP().toByteArray(), privKey1.getPrimeExponentQ().toByteArray(), privKey1.getCrtCoefficient().toByteArray()); assertNotSame(NULL, pkey1_copy); pkey2 = NativeCrypto.EVP_PKEY_new_RSA(privKey2.getModulus().toByteArray(), privKey2.getPublicExponent().toByteArray(), privKey2.getPrivateExponent().toByteArray(), privKey2.getPrimeP().toByteArray(), privKey2.getPrimeQ().toByteArray(), privKey2.getPrimeExponentP().toByteArray(), privKey2.getPrimeExponentQ().toByteArray(), privKey2.getCrtCoefficient().toByteArray()); assertNotSame(NULL, pkey2); try { NativeCrypto.EVP_PKEY_cmp(pkey1, NULL); fail("Should throw NullPointerException when arguments are NULL"); } catch (NullPointerException expected) { } try { NativeCrypto.EVP_PKEY_cmp(NULL, pkey1); fail("Should throw NullPointerException when arguments are NULL"); } catch (NullPointerException expected) { } 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)); } finally { if (pkey1 != 0) { NativeCrypto.EVP_PKEY_free(pkey1); } if (pkey1_copy != 0) { NativeCrypto.EVP_PKEY_free(pkey1_copy); } if (pkey2 != 0) { NativeCrypto.EVP_PKEY_free(pkey2); } } } 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); NativeCrypto.SSL_CTX_free(c2); } public void test_SSL_CTX_free() throws Exception { try { NativeCrypto.SSL_CTX_free(NULL); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new()); } public void test_SSL_CTX_set_session_id_context() throws Exception { byte[] empty = new byte[0]; try { NativeCrypto.SSL_CTX_set_session_id_context(NULL, empty); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); try { NativeCrypto.SSL_CTX_set_session_id_context(c, null); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_CTX_set_session_id_context(c, empty); NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[32]); try { NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]); } catch (IllegalArgumentException expected) { } NativeCrypto.SSL_CTX_free(c); } public void test_SSL_new() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertTrue(s != NULL); assertTrue((NativeCrypto.SSL_get_options(s) & 0x01000000L) != 0); // SSL_OP_NO_SSLv2 assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1) == 0); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_1) == 0); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_2) == 0); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_TLSEXT_PADDING) != 0); long s2 = NativeCrypto.SSL_new(c); assertTrue(s != s2); NativeCrypto.SSL_free(s2); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_use_certificate() throws Exception { try { NativeCrypto.SSL_use_certificate(NULL, null); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_use_certificate(s, null); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_use_certificate(s, getServerCertificates()); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception { initChannelIdKey(); try { NativeCrypto.SSL_set1_tls_channel_id(NULL, NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_set1_tls_channel_id(s, NULL); fail(); } catch (NullPointerException expected) { } // 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, CHANNEL_ID_PRIVATE_KEY.getPkeyContext()); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_use_PrivateKey() throws Exception { try { NativeCrypto.SSL_use_PrivateKey(NULL, NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_use_PrivateKey(s, NULL); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_check_private_key_null() throws Exception { try { NativeCrypto.SSL_check_private_key(NULL); fail(); } catch (NullPointerException expected) { } } public void test_SSL_check_private_key_no_key_no_cert() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); // neither private or certificate set try { NativeCrypto.SSL_check_private_key(s); fail(); } catch (SSLException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_check_private_key_cert_then_key() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); // first certificate, then private NativeCrypto.SSL_use_certificate(s, getServerCertificates()); try { NativeCrypto.SSL_check_private_key(s); fail(); } catch (SSLException expected) { } NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); NativeCrypto.SSL_check_private_key(s); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_check_private_key_key_then_cert() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); // first private, then certificate NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getPkeyContext()); try { NativeCrypto.SSL_check_private_key(s); fail(); } catch (SSLException expected) { } NativeCrypto.SSL_use_certificate(s, getServerCertificates()); NativeCrypto.SSL_check_private_key(s); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_get_mode() throws Exception { try { NativeCrypto.SSL_get_mode(NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertTrue(NativeCrypto.SSL_get_mode(s) != 0); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_set_mode_and_clear_mode() throws Exception { try { NativeCrypto.SSL_set_mode(NULL, 0); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); // check SSL_MODE_HANDSHAKE_CUTTHROUGH off by default assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH); // check SSL_MODE_CBC_RECORD_SPLITTING off by default assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_CBC_RECORD_SPLITTING); // set SSL_MODE_HANDSHAKE_CUTTHROUGH on NativeCrypto.SSL_set_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); assertTrue((NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0); // clear SSL_MODE_HANDSHAKE_CUTTHROUGH off NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); assertTrue((NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_get_options() throws Exception { try { NativeCrypto.SSL_get_options(NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertTrue(NativeCrypto.SSL_get_options(s) != 0); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_set_options() throws Exception { try { NativeCrypto.SSL_set_options(NULL, 0); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); NativeCrypto.SSL_set_options(s, NativeCrypto.SSL_OP_NO_SSLv3); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) != 0); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_clear_options() throws Exception { try { NativeCrypto.SSL_clear_options(NULL, 0); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); NativeCrypto.SSL_set_options(s, NativeCrypto.SSL_OP_NO_SSLv3); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) != 0); NativeCrypto.SSL_clear_options(s, NativeCrypto.SSL_OP_NO_SSLv3); assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_set_cipher_lists() throws Exception { try { NativeCrypto.SSL_set_cipher_lists(NULL, null); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_set_cipher_lists(s, null); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_set_cipher_lists(s, new String[] {}); try { NativeCrypto.SSL_set_cipher_lists(s, new String[] { null }); fail(); } catch (NullPointerException expected) { } // see OpenSSL ciphers man page String[] illegals = new String[] { // empty "", // never standardized "EXP1024-DES-CBC-SHA", "EXP1024-RC4-SHA", "DHE-DSS-RC4-SHA", // IDEA "IDEA-CBC-SHA", "IDEA-CBC-MD5" }; for (String illegal : illegals) { try { NativeCrypto.SSL_set_cipher_lists(s, new String[] { illegal }); fail(illegal); } catch (IllegalArgumentException expected) { } } List<String> ciphers = new ArrayList<String>(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.keySet()); NativeCrypto.SSL_set_cipher_lists(s, ciphers.toArray(new String[ciphers.size()])); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_set_verify() throws Exception { try { NativeCrypto.SSL_set_verify(NULL, 0); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_NONE); NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT); NativeCrypto.SSL_set_verify(s, (NativeCrypto.SSL_VERIFY_PEER | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT)); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } private static final boolean DEBUG = false; public static class Hooks { protected String negotiatedCipherSuite; private OpenSSLKey channelIdPrivateKey; protected boolean pskEnabled; protected byte[] pskKey; protected List<String> enabledCipherSuites; /** * @throws SSLException */ public long getContext() throws SSLException { return NativeCrypto.SSL_CTX_new(); } public long beforeHandshake(long context) throws SSLException { long s = NativeCrypto.SSL_new(context); // without this SSL_set_cipher_lists call the tests were // negotiating DHE-RSA-AES256-SHA by default which had // very slow ephemeral RSA key generation List<String> cipherSuites = new ArrayList<String>(); if (enabledCipherSuites == null) { cipherSuites.add("RC4-MD5"); 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); } NativeCrypto.SSL_set_cipher_lists( s, cipherSuites.toArray(new String[cipherSuites.size()])); if (channelIdPrivateKey != null) { NativeCrypto.SSL_set1_tls_channel_id(s, channelIdPrivateKey.getPkeyContext()); } return s; } public void configureCallbacks( @SuppressWarnings("unused") TestSSLHandshakeCallbacks callbacks) {} public void clientCertificateRequested(@SuppressWarnings("unused") long s) {} 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, fd, callback); } catch (IOException e) { } NativeCrypto.SSL_free(ssl); } if (context != NULL) { NativeCrypto.SSL_CTX_free(context); } if (socket != null) { socket.close(); } } } public static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks { private final Socket socket; private final long sslNativePointer; private final Hooks hooks; public TestSSLHandshakeCallbacks(Socket socket, long sslNativePointer, Hooks hooks) { this.socket = socket; this.sslNativePointer = sslNativePointer; this.hooks = hooks; } public long[] certificateChainRefs; public String authMethod; public boolean verifyCertificateChainCalled; @Override public void verifyCertificateChain(long sslSessionNativePtr, long[] certChainRefs, String authMethod) throws CertificateException { if (DEBUG) { System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) + " verifyCertificateChain" + " sessionPtr=0x" + Long.toString(sslSessionNativePtr, 16) + " asn1DerEncodedCertificateChain=" + Arrays.toString(certChainRefs) + " authMethod=" + authMethod); } this.certificateChainRefs = certChainRefs; this.authMethod = authMethod; this.verifyCertificateChainCalled = true; } public byte[] keyTypes; public byte[][] asn1DerEncodedX500Principals; public boolean clientCertificateRequestedCalled; @Override public void clientCertificateRequested(byte[] keyTypes, byte[][] asn1DerEncodedX500Principals) { if (DEBUG) { System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) + " clientCertificateRequested" + " keyTypes=" + keyTypes + " asn1DerEncodedX500Principals=" + asn1DerEncodedX500Principals); } this.keyTypes = keyTypes; this.asn1DerEncodedX500Principals = asn1DerEncodedX500Principals; this.clientCertificateRequestedCalled = true; if (hooks != null ) { hooks.clientCertificateRequested(sslNativePointer); } } public boolean handshakeCompletedCalled; @Override public void onSSLStateChange(long sslSessionNativePtr, int type, int val) { if (DEBUG) { System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16) + " onSSLStateChange"); } this.handshakeCompletedCalled = true; } public 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; } } public static class ClientHooks extends Hooks { protected 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, true); } return s; } } public static class ServerHooks extends Hooks { private final OpenSSLKey privateKey; private final long[] certificates; private boolean channelIdEnabled; private byte[] channelIdAfterHandshake; private Throwable channelIdAfterHandshakeException; protected String pskIdentityHint; public ServerHooks() { this(null, null); } public ServerHooks(OpenSSLKey privateKey, long[] certificates) { this.privateKey = privateKey; this.certificates = certificates; } @Override public long beforeHandshake(long c) throws SSLException { long s = super.beforeHandshake(c); if (privateKey != null) { NativeCrypto.SSL_use_PrivateKey(s, privateKey.getPkeyContext()); } if (certificates != null) { NativeCrypto.SSL_use_certificate(s, certificates); } if (channelIdEnabled) { NativeCrypto.SSL_enable_tls_channel_id(s); } if (pskEnabled) { NativeCrypto.set_SSL_psk_server_callback_enabled(s, true); NativeCrypto.SSL_use_psk_identity_hint(s, pskIdentityHint); } NativeCrypto.SSL_set_verify(s, NativeCrypto.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); } 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[] npnProtocols, final byte[] alpnProtocols) { 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 = socket.getFileDescriptor$(); 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=" + fd + " timeout=" + timeout + " client=" + client); } long session = NULL; try { session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client, npnProtocols, alpnProtocols); 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; } public void test_SSL_do_handshake_NULL_SSL() throws Exception { try { NativeCrypto.SSL_do_handshake(NULL, null, null, 0, false, null, null); fail(); } catch (NullPointerException expected) { } } public void test_SSL_do_handshake_null_args() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_do_handshake(s, null, null, 0, true, null, null); fail(); } catch (NullPointerException expected) { } try { NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0, true, null, null); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } public void test_SSL_do_handshake_normal() throws Exception { // normal client and server case final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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(getServerCertificates(), clientCallback.certificateChainRefs); assertEquals("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.handshakeCompletedCalled); assertTrue(serverCallback.handshakeCompletedCalled); } public void test_SSL_do_handshake_optional_client_certificate() throws Exception { // optional client certificate case final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public void clientCertificateRequested(long s) { super.clientCertificateRequested(s); NativeCrypto.SSL_use_PrivateKey(s, getClientPrivateKey().getPkeyContext()); NativeCrypto.SSL_use_certificate(s, getClientCertificates()); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public long beforeHandshake(long c) throws SSLException { long s = super.beforeHandshake(c); NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals()); NativeCrypto.SSL_set_verify(s, NativeCrypto.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(getServerCertificates(), clientCallback.certificateChainRefs); assertEquals("RSA", clientCallback.authMethod); assertTrue(serverCallback.verifyCertificateChainCalled); assertEqualCertificateChains(getClientCertificates(), serverCallback.certificateChainRefs); assertEquals("RSA", serverCallback.authMethod); assertTrue(clientCallback.clientCertificateRequestedCalled); assertNotNull(clientCallback.keyTypes); // this depends on the SSL_set_cipher_lists call in beforeHandshake // the three returned are the non-ephemeral cases. assertEquals(3, clientCallback.keyTypes.length); assertEquals("RSA", SSLParametersImpl.getClientKeyType(clientCallback.keyTypes[0])); assertEquals("DSA", SSLParametersImpl.getClientKeyType(clientCallback.keyTypes[1])); assertEquals("EC", SSLParametersImpl.getClientKeyType(clientCallback.keyTypes[2])); assertEqualPrincipals(getCaPrincipals(), clientCallback.asn1DerEncodedX500Principals); assertFalse(serverCallback.clientCertificateRequestedCalled); assertFalse(clientCallback.clientPSKKeyRequestedInvoked); assertFalse(serverCallback.clientPSKKeyRequestedInvoked); assertFalse(clientCallback.serverPSKKeyRequestedInvoked); assertFalse(serverCallback.serverPSKKeyRequestedInvoked); assertTrue(clientCallback.handshakeCompletedCalled); assertTrue(serverCallback.handshakeCompletedCalled); } public void test_SSL_do_handshake_missing_required_certificate() throws Exception { // required client certificate negative case final ServerSocket listener = new ServerSocket(0); try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public long beforeHandshake(long c) throws SSLException { long s = super.beforeHandshake(c); NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals()); NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER | NativeCrypto.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()); } } /** * Usually if a RuntimeException is thrown by the * clientCertificateRequestedCalled callback, the caller sees it * during the call to NativeCrypto_SSL_do_handshake. However, IIS * does not request client certs until after the initial * handshake. It does an SSL renegotiation, which means we need to * be able to deliver the callback's exception in cases like * SSL_read, SSL_write, and SSL_shutdown. */ public void test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate() throws Exception { final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public long beforeHandshake(long context) throws SSLException { long s = super.beforeHandshake(context); NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH); return s; } @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0); fail(); super.afterHandshake(session, s, c, sock, fd, callback); } @Override public void clientCertificateRequested(long s) { super.clientCertificateRequested(s); throw new RuntimeException("expected"); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { try { NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); NativeCrypto.SSL_set_options( s, NativeCrypto.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); NativeCrypto.SSL_renegotiate(s); NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, (int) ((TIMEOUT_SECONDS * 1000) / 2)); } catch (IOException expected) { } finally { 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); try { client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } catch (ExecutionException e) { if (!"expected".equals(e.getCause().getMessage())) { throw e; } } server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } public void test_SSL_do_handshake_client_timeout() throws Exception { // client timeout final ServerSocket listener = new ServerSocket(0); Socket serverSocket = null; try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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) { if (SocketTimeoutException.class != expected.getCause().getClass()) { expected.printStackTrace(); } assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); } finally { // Manually close peer socket when testing timeout IoUtils.closeQuietly(serverSocket); } } public void test_SSL_do_handshake_server_timeout() throws Exception { // server timeout final ServerSocket listener = new ServerSocket(0); Socket clientSocket = null; try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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); } } public void test_SSL_do_handshake_with_channel_id_normal() throws Exception { initChannelIdKey(); // Normal handshake with TLS Channel ID. final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks(); cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; // TLS Channel ID currently requires ECDHE-based key exchanges. cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"}); ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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(getServerCertificates(), 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.handshakeCompletedCalled); assertTrue(serverCallback.handshakeCompletedCalled); assertNull(sHooks.channelIdAfterHandshakeException); assertEqualByteArrays(CHANNEL_ID, sHooks.channelIdAfterHandshake); } 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 = new ServerSocket(0); Hooks cHooks = new Hooks(); cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY; // TLS Channel ID currently requires ECDHE-based key exchanges. cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"}); ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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(getServerCertificates(), 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.handshakeCompletedCalled); assertTrue(serverCallback.handshakeCompletedCalled); assertNull(sHooks.channelIdAfterHandshakeException); assertNull(sHooks.channelIdAfterHandshake); } 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 = new ServerSocket(0); Hooks cHooks = new Hooks(); cHooks.channelIdPrivateKey = null; // TLS Channel ID currently requires ECDHE-based key exchanges. cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"}); ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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(getServerCertificates(), 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.handshakeCompletedCalled); assertTrue(serverCallback.handshakeCompletedCalled); assertNull(sHooks.channelIdAfterHandshakeException); assertNull(sHooks.channelIdAfterHandshake); } public void test_SSL_do_handshake_with_psk_normal() throws Exception { // normal TLS-PSK client and server case final ServerSocket listener = new ServerSocket(0); 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.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); } 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 = new ServerSocket(0); 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.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); } 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 = new ServerSocket(0); 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); } public void test_SSL_do_handshake_with_psk_key_mismatch() throws Exception { final ServerSocket listener = new ServerSocket(0); 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()); } } public void test_SSL_do_handshake_with_psk_with_no_client_key() throws Exception { final ServerSocket listener = new ServerSocket(0); 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()); } } public void test_SSL_do_handshake_with_psk_with_no_server_key() throws Exception { final ServerSocket listener = new ServerSocket(0); 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()); } } public void test_SSL_do_handshake_with_psk_key_too_long() throws Exception { final ServerSocket listener = new ServerSocket(0); 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()); } } public void test_SSL_use_psk_identity_hint() throws Exception { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_use_psk_identity_hint(s, null); NativeCrypto.SSL_use_psk_identity_hint(s, "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, pskIdentityHint.toString()); fail(); } catch (SSLException expected) { } } finally { NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } } public void test_SSL_set_session() throws Exception { try { NativeCrypto.SSL_set_session(NULL, NULL); fail(); } catch (NullPointerException expected) { } { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); NativeCrypto.SSL_set_session(s, NULL); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } { final long clientContext = NativeCrypto.SSL_CTX_new(); final long serverContext = NativeCrypto.SSL_CTX_new(); final ServerSocket listener = new ServerSocket(0); 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(), getServerCertificates()) { @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); NativeCrypto.SSL_set_session(s, 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(), getServerCertificates()) { @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); NativeCrypto.SSL_CTX_free(clientContext); } } public void test_SSL_set_session_creation_enabled() throws Exception { try { NativeCrypto.SSL_set_session_creation_enabled(NULL, false); fail(); } catch (NullPointerException expected) { } { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); NativeCrypto.SSL_set_session_creation_enabled(s, false); NativeCrypto.SSL_set_session_creation_enabled(s, true); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } final ServerSocket listener = new ServerSocket(0); // negative test case for SSL_set_session_creation_enabled(false) on client try { Hooks cHooks = new Hooks() { @Override public long beforeHandshake(long c) throws SSLException { long s = super.beforeHandshake(c); NativeCrypto.SSL_set_session_creation_enabled(s, false); return s; } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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(SSLProtocolException.class, expected.getCause().getClass()); } // negative test case for SSL_set_session_creation_enabled(false) on server try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public long beforeHandshake(long c) throws SSLException { long s = super.beforeHandshake(c); NativeCrypto.SSL_set_session_creation_enabled(s, 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); client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); fail(); } catch (ExecutionException expected) { assertEquals(SSLProtocolException.class, expected.getCause().getClass()); } } public void test_SSL_set_tlsext_host_name() throws Exception { // NULL SSL try { NativeCrypto.SSL_set_tlsext_host_name(NULL, null); fail(); } catch (NullPointerException expected) { } final String hostname = "www.android.com"; { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); // null hostname try { NativeCrypto.SSL_set_tlsext_host_name(s, null); fail(); } catch (NullPointerException expected) { } // too long hostname try { char[] longHostname = new char[256]; Arrays.fill(longHostname, 'w'); NativeCrypto.SSL_set_tlsext_host_name(s, new String(longHostname)); fail(); } catch (SSLException expected) { } assertNull(NativeCrypto.SSL_get_servername(s)); NativeCrypto.SSL_set_tlsext_host_name(s, new String(hostname)); assertEquals(hostname, NativeCrypto.SSL_get_servername(s)); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } final ServerSocket listener = new ServerSocket(0); // 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, hostname); return s; } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @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)); 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); } public void test_SSL_NpnNegotiateSuccess() throws Exception { final byte[] clientNpnProtocols = new byte[] { 8, 'h', 't', 't', 'p', '/', '1', '.', '1', 3, 'f', 'o', 'o', 6, 's', 'p', 'd', 'y', '/', '2', }; final byte[] serverNpnProtocols = new byte[] { 6, 's', 'p', 'd', 'y', '/', '2', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', }; Hooks cHooks = new Hooks() { @Override public long beforeHandshake(long context) throws SSLException { NativeCrypto.SSL_CTX_enable_npn(context); return super.beforeHandshake(context); } @Override public void afterHandshake(long session, long ssl, long context, Socket socket, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl); assertEquals("spdy/2", new String(negotiated)); assertTrue("NPN should enable cutthrough on the client", 0 != (NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH)); NativeCrypto.SSL_write(ssl, fd, callback, new byte[] { 42 }, 0, 1, (int) ((TIMEOUT_SECONDS * 1000) / 2)); super.afterHandshake(session, ssl, context, socket, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public long beforeHandshake(long context) throws SSLException { NativeCrypto.SSL_CTX_enable_npn(context); return super.beforeHandshake(context); } @Override public void afterHandshake(long session, long ssl, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl); assertEquals("spdy/2", new String(negotiated)); assertEquals("NPN should not enable cutthrough on the server", 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); byte[] buffer = new byte[1]; NativeCrypto.SSL_read(ssl, fd, callback, buffer, 0, 1, 0); assertEquals(42, buffer[0]); super.afterHandshake(session, ssl, c, sock, fd, callback); } }; ServerSocket listener = new ServerSocket(0); Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, clientNpnProtocols, null); Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, serverNpnProtocols, null); client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } public void test_SSL_AlpnNegotiateSuccess() throws Exception { final byte[] clientAlpnProtocols = new byte[] { 8, 'h', 't', 't', 'p', '/', '1', '.', '1', 3, 'f', 'o', 'o', 6, 's', 'p', 'd', 'y', '/', '2', }; final byte[] serverAlpnProtocols = new byte[] { 6, 's', 'p', 'd', 'y', '/', '2', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', }; Hooks cHooks = new Hooks() { @Override public long beforeHandshake(long context) throws SSLException { long sslContext = super.beforeHandshake(context); NativeCrypto.SSL_set_alpn_protos(sslContext, clientAlpnProtocols); return sslContext; } @Override public void afterHandshake(long session, long ssl, long context, Socket socket, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl); assertEquals("spdy/2", new String(negotiated)); /* * There is no callback on the client, so we can't enable * cut-through */ assertEquals("ALPN should not enable cutthrough on the client", 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); super.afterHandshake(session, ssl, context, socket, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public void afterHandshake(long session, long ssl, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl); assertEquals("spdy/2", new String(negotiated)); assertEquals("ALPN should not enable cutthrough on the server", 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH); super.afterHandshake(session, ssl, c, sock, fd, callback); } }; ServerSocket listener = new ServerSocket(0); Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null); Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, serverAlpnProtocols); client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } public void test_SSL_get_servername_null() throws Exception { // NULL SSL try { NativeCrypto.SSL_get_servername(NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); assertNull(NativeCrypto.SSL_get_servername(s)); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); // additional positive testing by test_SSL_set_tlsext_host_name } public void test_SSL_renegotiate() throws Exception { try { NativeCrypto.SSL_renegotiate(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { byte[] buffer = new byte[1]; NativeCrypto.SSL_read(s, fd, callback, buffer, 0, 1, 0); assertEquals(42, buffer[0]); super.afterHandshake(session, s, c, sock, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { NativeCrypto.SSL_renegotiate(s); NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 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); } public void test_SSL_get_certificate() throws Exception { try { NativeCrypto.SSL_get_certificate(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { assertNull(NativeCrypto.SSL_get_certificate(s)); super.afterHandshake(session, s, c, sock, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { assertEqualCertificateChains( getServerCertificates(), NativeCrypto.SSL_get_certificate(s)); 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); } public void test_SSL_get_peer_cert_chain() throws Exception { try { NativeCrypto.SSL_get_peer_cert_chain(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { long[] cc = NativeCrypto.SSL_get_peer_cert_chain(s); assertEqualCertificateChains(getServerCertificates(), cc); for (long ref : cc) { NativeCrypto.X509_free(ref); } super.afterHandshake(session, s, c, sock, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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); } final byte[] BYTES = new byte[] { 2, -3, 5, 127, 0, -128 }; public void test_SSL_read() throws Exception { // NULL ssl try { NativeCrypto.SSL_read(NULL, null, null, null, 0, 0, 0); fail(); } catch (NullPointerException expected) { } // null FileDescriptor { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_read(s, null, DUMMY_CB, null, 0, 0, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // null SSLHandshakeCallbacks { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_read(s, INVALID_FD, null, null, 0, 0, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // null byte array { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, null, 0, 0, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // handshaking not yet performed { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); fail(); } catch (SSLException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } final ServerSocket listener = new ServerSocket(0); // 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, 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(), getServerCertificates()) { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { NativeCrypto.SSL_write(s, 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, fd, callback, new byte[1], 0, 1, 1); fail(); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { NativeCrypto.SSL_read(s, 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()); } } public void test_SSL_write() throws Exception { try { NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0); fail(); } catch (NullPointerException expected) { } // null FileDescriptor { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // null SSLHandshakeCallbacks { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // null byte array { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0); fail(); } catch (NullPointerException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // handshaking not yet performed { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); try { NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0); fail(); } catch (SSLException expected) { } NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } // positively tested by test_SSL_read } public void test_SSL_interrupt() throws Exception { // SSL_interrupt is a rare case that tolerates a null SSL argument NativeCrypto.SSL_interrupt(NULL); // also works without handshaking { long c = NativeCrypto.SSL_CTX_new(); long s = NativeCrypto.SSL_new(c); NativeCrypto.SSL_interrupt(s); NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } final ServerSocket listener = new ServerSocket(0); 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, fd, callback, new byte[1], 0, 1, 0); super.afterHandshake(session, s, c, sock, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) { @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(1*1000); NativeCrypto.SSL_interrupt(s); } catch (Exception e) { } } }.start(); assertEquals(-1, NativeCrypto.SSL_read(s, 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); try { task.run(s); } finally { NativeCrypto.SSL_free(s); NativeCrypto.SSL_CTX_free(c); } } public void test_SSL_shutdown() throws Exception { // null FileDescriptor wrapWithSSLSession(new SSLSessionWrappedTask() { @Override public void run(long sslSession) throws Exception { try { NativeCrypto.SSL_shutdown(sslSession, null, DUMMY_CB); fail(); } catch (NullPointerException expected) { } } }); // null SSLHandshakeCallbacks wrapWithSSLSession(new SSLSessionWrappedTask() { @Override public void run(long sslSession) throws Exception { try { NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, null); fail(); } catch (NullPointerException expected) { } } }); // SSL_shutdown is a rare case that tolerates a null SSL argument NativeCrypto.SSL_shutdown(NULL, INVALID_FD, DUMMY_CB); // handshaking not yet performed wrapWithSSLSession(new SSLSessionWrappedTask() { @Override public void run(long sslSession) throws Exception { try { NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, DUMMY_CB); fail(); } catch (SocketException expected) { } } }); // positively tested elsewhere because handshake uses use // SSL_shutdown to ensure SSL_SESSIONs are reused. } public void test_SSL_free() throws Exception { try { NativeCrypto.SSL_free(NULL); fail(); } catch (NullPointerException expected) { } long c = NativeCrypto.SSL_CTX_new(); NativeCrypto.SSL_free(NativeCrypto.SSL_new(c)); NativeCrypto.SSL_CTX_free(c); // additional positive testing elsewhere because handshake // uses use SSL_free to cleanup in afterHandshake. } public void test_SSL_SESSION_session_id() throws Exception { try { NativeCrypto.SSL_SESSION_session_id(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); 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(), getServerCertificates()); 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); } public void test_SSL_SESSION_get_time() throws Exception { try { NativeCrypto.SSL_SESSION_get_time(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); { 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(), getServerCertificates()); 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); } } public void test_SSL_SESSION_get_version() throws Exception { try { NativeCrypto.SSL_SESSION_get_version(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); 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(), getServerCertificates()); 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); } public void test_SSL_SESSION_cipher() throws Exception { try { NativeCrypto.SSL_SESSION_cipher(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks() { @Override public void afterHandshake(long session, long s, long c, Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { String a = NativeCrypto.SSL_SESSION_cipher(session); assertTrue(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.containsKey(a)); super.afterHandshake(session, s, c, sock, fd, callback); } }; Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); 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); } public void test_SSL_SESSION_free() throws Exception { try { NativeCrypto.SSL_SESSION_free(NULL); fail(); } catch (NullPointerException expected) { } // additional positive testing elsewhere because handshake // uses use SSL_SESSION_free to cleanup in afterHandshake. } public void test_i2d_SSL_SESSION() throws Exception { try { NativeCrypto.i2d_SSL_SESSION(NULL); fail(); } catch (NullPointerException expected) { } final ServerSocket listener = new ServerSocket(0); 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(), getServerCertificates()); 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); } public void test_d2i_SSL_SESSION() throws Exception { try { NativeCrypto.d2i_SSL_SESSION(null); fail(); } catch (NullPointerException expected) { } assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[0])); assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[1])); // positive testing by test_i2d_SSL_SESSION } 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 } public void test_ENGINE_by_id_Failure() throws Exception { NativeCrypto.ENGINE_load_dynamic(); long engine = NativeCrypto.ENGINE_by_id("non-existent"); if (engine != 0) { NativeCrypto.ENGINE_free(engine); fail("should not acquire reference to non-existent engine"); } } /** * Loads the test OpenSSL ENGINE. If it's already loaded, returns * immediately. */ public static void loadTestEngine() throws Exception { long testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); if (testEngine != 0) { NativeCrypto.ENGINE_free(testEngine); return; } NativeCrypto.ENGINE_load_dynamic(); long dynEngine = NativeCrypto.ENGINE_by_id("dynamic"); try { ClassLoader loader = NativeCryptoTest.class.getClassLoader(); final String libraryPaths; if (loader instanceof BaseDexClassLoader) { libraryPaths = ((BaseDexClassLoader) loader).getLdLibraryPath(); } else { libraryPaths = System.getProperty("java.library.path"); } assertNotNull(libraryPaths); String[] libraryPathArray = libraryPaths.split(":"); for (String path : libraryPathArray) { assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "DIR_ADD", path, 0)); } // We must add this to the list of ENGINEs assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LIST_ADD", "2", 0)); // Do a direct load of the ENGINE. assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "ID", TEST_ENGINE_ID, 0)); assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LOAD", null, 0)); } finally { NativeCrypto.ENGINE_free(dynEngine); } testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); if (testEngine == 0) { fail("could not load test engine"); } NativeCrypto.ENGINE_free(testEngine); } public void test_ENGINE_by_id_TestEngine() throws Exception { loadTestEngine(); long engine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID); assertTrue(engine != 0); NativeCrypto.ENGINE_add(engine); NativeCrypto.ENGINE_init(engine); long pkey = NULL; try { final String rsaPem = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXAIBAAKBgQCvvsYz1VKhU9PT0NHlotX22tcCjeaiVFNg0JrkjoK2XuMb+7a6\n" + "R5bzgIr24+OnBB0LqgaKnHwxZTA73lo/Wy/Ms5Kvg4yX9UMkNE+PvH5vzcQBbFdI\n" + "lwETFPvFokHO5OyOcEY+iVWG2fDloteH2JsrKYLh9Sx3Br5pHFCCm5qT5wIDAQAB\n" + "AoGAWDxoNs371pPH3qkROUIwOuhU2ytziDzeP9V8bxQ9/GJXlE0kyRH4b/kxzBNO\n" + "0SP3kUukTSOUFxi+xtA0b2rQ7Be2txtjzW1TGOHSCWbFrJAdTqeBcmQJSaZay8n1\n" + "LOpk4/zvBl7VScBth1IgXP44v6lOzthsrDhMlUYs07ymwYECQQDonaLOhkmVThPa\n" + "CIThdE5CN/wF5UDzGOz+ZBz3dt8D8QQMu0aZaPzibq9BC462j/fWeWS5OFzbq2+T\n" + "+cor3nwPAkEAwWmTQdra6GMPEc40zNsM5ehF2FjOpX8aU8267eG56y0Y+GbHx2BN\n" + "zAHfPxGBBH8cZ0cLhk4RSo/po7Vv+cRyqQJAAQz1N0mT+4Cmxk1TjFEiKVpnYP9w\n" + "E6kBKQT6vINk7negNQ6Dex3mRn+Jexm6Q0jTLbzOn6eJg9R6ZIi0SQ5wMQJAKX2n\n" + "fGohqdaORgiRZRzcsHlaemXatsAEetPYdO2Gf7/l6mvKEahEKC6CoLn1jmxiQHmK\n" + "LF6U8QTcXyUuB0uwOQJBAIwWWjQGGc2sAQ1HW0C2wwCQbWneeBkiRBedonDBHtiB\n" + "Wz0zS2CMCtBPNeHQmmsXH2Ca+ADdh53sKTuperLiuiw=\n" + "-----END RSA PRIVATE KEY-----"; pkey = NativeCrypto.ENGINE_load_private_key(engine, rsaPem); assertTrue(pkey != 0); } finally { if (pkey != NULL) { NativeCrypto.EVP_PKEY_free(pkey); } NativeCrypto.ENGINE_free(engine); NativeCrypto.ENGINE_finish(engine); } } public void test_RAND_bytes_Success() throws Exception { byte[] output = new byte[128]; NativeCrypto.RAND_bytes(output); boolean isZero = true; for (int i = 0; i < output.length; i++) { isZero &= (output[i] == 0); } assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) " + "and probably indicates an error.", isZero); } public void test_RAND_bytes_Null_Failure() throws Exception { byte[] output = null; try { NativeCrypto.RAND_bytes(output); fail("Should be an error on null buffer input"); } catch (RuntimeException expected) { } } public void test_EVP_get_digestbyname() throws Exception { assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL); try { NativeCrypto.EVP_get_digestbyname(null); fail(); } catch (NullPointerException expected) { } try { NativeCrypto.EVP_get_digestbyname(""); NativeCrypto.EVP_get_digestbyname("foobar"); fail(); } catch (RuntimeException expected) { } } public void test_EVP_SignInit() throws Exception { final OpenSSLDigestContext ctx = new OpenSSLDigestContext(NativeCrypto.EVP_MD_CTX_create()); assertEquals(1, NativeCrypto.EVP_SignInit(ctx, NativeCrypto.EVP_get_digestbyname("sha256"))); try { NativeCrypto.EVP_SignInit(ctx, 0); fail(); } catch (RuntimeException expected) { } } public void test_get_RSA_private_params() throws Exception { try { NativeCrypto.get_RSA_private_params(NULL); } catch (NullPointerException expected) { } try { NativeCrypto.get_RSA_private_params(NULL); } catch (NullPointerException expected) { } // Test getting params for the wrong kind of key. final byte[] seed = new byte[20]; long ctx = 0; try { ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); assertTrue(ctx != NULL); try { NativeCrypto.get_RSA_private_params(ctx); fail(); } catch (RuntimeException expected) { } } finally { if (ctx != 0) { NativeCrypto.EVP_PKEY_free(ctx); } } } public void test_get_RSA_public_params() throws Exception { try { NativeCrypto.get_RSA_public_params(NULL); } catch (NullPointerException expected) { } try { NativeCrypto.get_RSA_public_params(NULL); } catch (NullPointerException expected) { } // Test getting params for the wrong kind of key. final byte[] seed = new byte[20]; long ctx = 0; try { ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); assertTrue(ctx != NULL); try { NativeCrypto.get_RSA_public_params(ctx); fail(); } catch (RuntimeException expected) { } } finally { if (ctx != 0) { NativeCrypto.EVP_PKEY_free(ctx); } } } public void test_RSA_size_null_key_Failure() throws Exception { try { NativeCrypto.RSA_size(0); fail(); } catch (NullPointerException expected) {} } public void test_RSA_private_encrypt_null_key_Failure() throws Exception { try { NativeCrypto.RSA_private_encrypt(0, new byte[0], new byte[0], 0, 0); fail(); } catch (NullPointerException expected) {} } public void test_RSA_private_decrypt_null_key_Failure() throws Exception { try { NativeCrypto.RSA_private_decrypt(0, new byte[0], new byte[0], 0, 0); fail(); } catch (NullPointerException expected) {} } public void test_RSA_public_encrypt_null_key_Failure() throws Exception { try { NativeCrypto.RSA_public_encrypt(0, new byte[0], new byte[0], 0, 0); fail(); } catch (NullPointerException expected) {} } public void test_RSA_public_decrypt_null_key_Failure() throws Exception { try { NativeCrypto.RSA_public_decrypt(0, new byte[0], new byte[0], 0, 0); fail(); } catch (NullPointerException expected) {} } final byte[] dsa2048_p = { (byte) 0x00, (byte) 0xC3, (byte) 0x16, (byte) 0xD4, (byte) 0xBA, (byte) 0xDC, (byte) 0x0E, (byte) 0xB8, (byte) 0xFC, (byte) 0x40, (byte) 0xDB, (byte) 0xB0, (byte) 0x76, (byte) 0x47, (byte) 0xB8, (byte) 0x8D, (byte) 0xC1, (byte) 0xF1, (byte) 0xAB, (byte) 0x9B, (byte) 0x80, (byte) 0x9D, (byte) 0xDC, (byte) 0x55, (byte) 0x33, (byte) 0xEC, (byte) 0xB6, (byte) 0x09, (byte) 0x8F, (byte) 0xB7, (byte) 0xD9, (byte) 0xA5, (byte) 0x7F, (byte) 0xC1, (byte) 0xE3, (byte) 0xAD, (byte) 0xE1, (byte) 0x7A, (byte) 0x58, (byte) 0xF4, (byte) 0x2D, (byte) 0xB9, (byte) 0x61, (byte) 0xCF, (byte) 0x5B, (byte) 0xCA, (byte) 0x41, (byte) 0x9F, (byte) 0x73, (byte) 0x8D, (byte) 0x81, (byte) 0x62, (byte) 0xD2, (byte) 0x19, (byte) 0x7D, (byte) 0x18, (byte) 0xDB, (byte) 0xB3, (byte) 0x04, (byte) 0xE7, (byte) 0xB2, (byte) 0x28, (byte) 0x59, (byte) 0x14, (byte) 0x73, (byte) 0x43, (byte) 0xF1, (byte) 0x45, (byte) 0xC7, (byte) 0x47, (byte) 0xCC, (byte) 0xD1, (byte) 0x12, (byte) 0x8E, (byte) 0x19, (byte) 0x00, (byte) 0x2C, (byte) 0xD0, (byte) 0x86, (byte) 0x54, (byte) 0x64, (byte) 0x2D, (byte) 0x42, (byte) 0x6C, (byte) 0x6B, (byte) 0x5C, (byte) 0x2D, (byte) 0x4D, (byte) 0x97, (byte) 0x6A, (byte) 0x1D, (byte) 0x89, (byte) 0xB1, (byte) 0x2C, (byte) 0xA0, (byte) 0x05, (byte) 0x2B, (byte) 0x3C, (byte) 0xDB, (byte) 0x1F, (byte) 0x89, (byte) 0x03, (byte) 0x03, (byte) 0x92, (byte) 0x63, (byte) 0xB6, (byte) 0x08, (byte) 0x32, (byte) 0x50, (byte) 0xB2, (byte) 0x54, (byte) 0xA3, (byte) 0xFE, (byte) 0x6C, (byte) 0x35, (byte) 0x17, (byte) 0x2F, (byte) 0x7F, (byte) 0x54, (byte) 0xA4, (byte) 0xAE, (byte) 0x96, (byte) 0x1E, (byte) 0x31, (byte) 0x83, (byte) 0xF1, (byte) 0x3F, (byte) 0x9E, (byte) 0xB9, (byte) 0x5D, (byte) 0xD3, (byte) 0xA9, (byte) 0xCB, (byte) 0xE5, (byte) 0x2F, (byte) 0xBC, (byte) 0xA4, (byte) 0x1A, (byte) 0x31, (byte) 0x41, (byte) 0x91, (byte) 0x2C, (byte) 0xA0, (byte) 0xF4, (byte) 0x83, (byte) 0xAC, (byte) 0xD5, (byte) 0xBA, (byte) 0x3D, (byte) 0x19, (byte) 0xED, (byte) 0xF1, (byte) 0x6C, (byte) 0xD9, (byte) 0x3F, (byte) 0x30, (byte) 0xDA, (byte) 0x80, (byte) 0x06, (byte) 0x56, (byte) 0x3A, (byte) 0x8C, (byte) 0x74, (byte) 0x63, (byte) 0xF2, (byte) 0xED, (byte) 0x1E, (byte) 0xE3, (byte) 0x86, (byte) 0x95, (byte) 0x64, (byte) 0x2A, (byte) 0xC4, (byte) 0x5F, (byte) 0xB2, (byte) 0x64, (byte) 0x40, (byte) 0x9D, (byte) 0xA6, (byte) 0xB8, (byte) 0xF5, (byte) 0x84, (byte) 0x03, (byte) 0x2E, (byte) 0x4A, (byte) 0x7A, (byte) 0x1A, (byte) 0xB0, (byte) 0x0E, (byte) 0xBA, (byte) 0xB1, (byte) 0xF5, (byte) 0xD2, (byte) 0xE7, (byte) 0x65, (byte) 0xCE, (byte) 0xEE, (byte) 0x2C, (byte) 0x7C, (byte) 0x68, (byte) 0x20, (byte) 0x50, (byte) 0x53, (byte) 0x0F, (byte) 0x60, (byte) 0x92, (byte) 0x81, (byte) 0xC0, (byte) 0x2C, (byte) 0x2A, (byte) 0xEA, (byte) 0xE9, (byte) 0xB3, (byte) 0x2A, (byte) 0x81, (byte) 0xDA, (byte) 0x0F, (byte) 0xBB, (byte) 0xFA, (byte) 0x5B, (byte) 0x47, (byte) 0xDA, (byte) 0x57, (byte) 0x4E, (byte) 0xFC, (byte) 0x05, (byte) 0x2C, (byte) 0x6A, (byte) 0x90, (byte) 0xA0, (byte) 0x99, (byte) 0x88, (byte) 0x71, (byte) 0x8A, (byte) 0xCC, (byte) 0xD2, (byte) 0x97, (byte) 0x11, (byte) 0xB1, (byte) 0xCE, (byte) 0xF7, (byte) 0x47, (byte) 0x53, (byte) 0x53, (byte) 0x68, (byte) 0xE1, (byte) 0x2A, (byte) 0x56, (byte) 0xD5, (byte) 0x3D, (byte) 0xDF, (byte) 0x08, (byte) 0x16, (byte) 0x1F, (byte) 0xAA, (byte) 0x54, (byte) 0x15, }; final byte[] dsa2048_q = { (byte) 0x00, (byte) 0xAA, (byte) 0xDD, (byte) 0xE2, (byte) 0xCE, (byte) 0x08, (byte) 0xC0, (byte) 0x0E, (byte) 0x91, (byte) 0x8C, (byte) 0xD9, (byte) 0xBC, (byte) 0x1E, (byte) 0x05, (byte) 0x70, (byte) 0x07, (byte) 0x3B, (byte) 0xB5, (byte) 0xA9, (byte) 0xB5, (byte) 0x8B, (byte) 0x21, (byte) 0x68, (byte) 0xA2, (byte) 0x76, (byte) 0x53, (byte) 0x1E, (byte) 0x68, (byte) 0x1B, (byte) 0x4F, (byte) 0x88, (byte) 0x6D, (byte) 0xCF, }; final byte[] dsa2048_g = { (byte) 0x6B, (byte) 0x4D, (byte) 0x21, (byte) 0x92, (byte) 0x24, (byte) 0x76, (byte) 0xE5, (byte) 0xA2, (byte) 0xCE, (byte) 0x02, (byte) 0x85, (byte) 0x32, (byte) 0x73, (byte) 0x70, (byte) 0xFF, (byte) 0xB9, (byte) 0xD4, (byte) 0x51, (byte) 0xBA, (byte) 0x22, (byte) 0x8B, (byte) 0x75, (byte) 0x29, (byte) 0xE3, (byte) 0xF2, (byte) 0x2E, (byte) 0x20, (byte) 0xF5, (byte) 0x6A, (byte) 0xD9, (byte) 0x75, (byte) 0xA0, (byte) 0xC0, (byte) 0x3B, (byte) 0x12, (byte) 0x2F, (byte) 0x4F, (byte) 0x9A, (byte) 0xF8, (byte) 0x5D, (byte) 0x45, (byte) 0xC5, (byte) 0x80, (byte) 0x6C, (byte) 0x9B, (byte) 0x56, (byte) 0xBE, (byte) 0x8E, (byte) 0x40, (byte) 0xF9, (byte) 0x0A, (byte) 0xF0, (byte) 0x3D, (byte) 0xD7, (byte) 0x7C, (byte) 0xDE, (byte) 0x22, (byte) 0x10, (byte) 0x24, (byte) 0xCC, (byte) 0xAE, (byte) 0x8A, (byte) 0xC0, (byte) 0x05, (byte) 0xCD, (byte) 0xDC, (byte) 0x10, (byte) 0x29, (byte) 0x4D, (byte) 0xFC, (byte) 0xEC, (byte) 0xEF, (byte) 0x51, (byte) 0x4B, (byte) 0xF9, (byte) 0xCC, (byte) 0x99, (byte) 0x84, (byte) 0x1B, (byte) 0x14, (byte) 0x68, (byte) 0xEC, (byte) 0xF0, (byte) 0x5E, (byte) 0x07, (byte) 0x10, (byte) 0x09, (byte) 0xA9, (byte) 0x2C, (byte) 0x04, (byte) 0xD0, (byte) 0x14, (byte) 0xBF, (byte) 0x88, (byte) 0x9E, (byte) 0xBB, (byte) 0xE3, (byte) 0x3F, (byte) 0xDE, (byte) 0x92, (byte) 0xE1, (byte) 0x64, (byte) 0x07, (byte) 0x28, (byte) 0xC1, (byte) 0xCA, (byte) 0x48, (byte) 0xC1, (byte) 0x1D, (byte) 0x33, (byte) 0xE4, (byte) 0x35, (byte) 0xBE, (byte) 0xDF, (byte) 0x5E, (byte) 0x50, (byte) 0xF9, (byte) 0xC2, (byte) 0x0E, (byte) 0x25, (byte) 0x0D, (byte) 0x20, (byte) 0x8C, (byte) 0x01, (byte) 0x0A, (byte) 0x23, (byte) 0xD4, (byte) 0x6E, (byte) 0x42, (byte) 0x47, (byte) 0xE1, (byte) 0x9E, (byte) 0x36, (byte) 0x91, (byte) 0xC8, (byte) 0x65, (byte) 0x44, (byte) 0xE0, (byte) 0x04, (byte) 0x86, (byte) 0x2F, (byte) 0xD4, (byte) 0x90, (byte) 0x16, (byte) 0x09, (byte) 0x14, (byte) 0xB1, (byte) 0xC5, (byte) 0x7D, (byte) 0xB2, (byte) 0x7C, (byte) 0x36, (byte) 0x0D, (byte) 0x9C, (byte) 0x1F, (byte) 0x83, (byte) 0x57, (byte) 0x94, (byte) 0x26, (byte) 0x32, (byte) 0x9C, (byte) 0x86, (byte) 0x8E, (byte) 0xE5, (byte) 0x80, (byte) 0x3A, (byte) 0xA9, (byte) 0xAF, (byte) 0x4A, (byte) 0x95, (byte) 0x78, (byte) 0x8D, (byte) 0xE6, (byte) 0xC3, (byte) 0x0C, (byte) 0x78, (byte) 0x83, (byte) 0x4B, (byte) 0xF5, (byte) 0x40, (byte) 0x04, (byte) 0x20, (byte) 0x90, (byte) 0x5C, (byte) 0xA1, (byte) 0x19, (byte) 0xEB, (byte) 0x95, (byte) 0x70, (byte) 0x2B, (byte) 0x94, (byte) 0xA3, (byte) 0x43, (byte) 0xDD, (byte) 0xEB, (byte) 0xD4, (byte) 0x0C, (byte) 0xBC, (byte) 0xBD, (byte) 0x58, (byte) 0x2D, (byte) 0x75, (byte) 0xB0, (byte) 0x8D, (byte) 0x8B, (byte) 0x70, (byte) 0xB9, (byte) 0xE7, (byte) 0xA3, (byte) 0xCC, (byte) 0x8C, (byte) 0xB4, (byte) 0xCD, (byte) 0xBB, (byte) 0x4B, (byte) 0xB1, (byte) 0x15, (byte) 0x18, (byte) 0x79, (byte) 0xDF, (byte) 0x22, (byte) 0xA6, (byte) 0x5C, (byte) 0x90, (byte) 0x7C, (byte) 0x1F, (byte) 0xEA, (byte) 0x1B, (byte) 0xF2, (byte) 0x89, (byte) 0x87, (byte) 0xB2, (byte) 0xEC, (byte) 0x57, (byte) 0xFF, (byte) 0xB2, (byte) 0xDA, (byte) 0xF5, (byte) 0xAD, (byte) 0x73, (byte) 0xC0, (byte) 0xA0, (byte) 0x20, (byte) 0x8B, (byte) 0x78, (byte) 0xA1, (byte) 0x5D, (byte) 0x04, (byte) 0x0A, (byte) 0x29, (byte) 0xE3, (byte) 0xD7, (byte) 0x37, (byte) 0xF6, (byte) 0xA2, (byte) 0xCA, }; public void test_DSA_generate_key() throws Exception { final byte[] seed = new byte[20]; // Real key { long ctx = 0; try { ctx = NativeCrypto.DSA_generate_key(2048, seed, dsa2048_g, dsa2048_p, dsa2048_q); assertTrue(ctx != NULL); } finally { if (ctx != 0) { NativeCrypto.EVP_PKEY_free(ctx); } } } // Real key with minimum bit size (should be 512 bits) { long ctx = 0; try { ctx = NativeCrypto.DSA_generate_key(0, null, null, null, null); assertTrue(ctx != NULL); } finally { if (ctx != 0) { NativeCrypto.EVP_PKEY_free(ctx); } } } // Bad DSA params. { long ctx = 0; try { ctx = NativeCrypto.DSA_generate_key(0, null, new byte[] {}, new byte[] {}, new byte[] {}); fail(); } catch (RuntimeException expected) { } finally { if (ctx != 0) { NativeCrypto.EVP_PKEY_free(ctx); } } } } public void test_get_DSA_params_null_key_Failure() throws Exception { try { NativeCrypto.get_DSA_params(0); fail(); } catch (NullPointerException expected) {} } public void test_set_DSA_flag_nonce_from_hash_null_key_Failure() throws Exception { try { NativeCrypto.set_DSA_flag_nonce_from_hash(0); fail(); } catch (NullPointerException expected) {} } /* * 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, }; public void testEC_GROUP() throws Exception { /* Test using NIST's P-256 curve */ check_EC_GROUP(NativeCrypto.EC_CURVE_GFP, "prime256v1", "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1L); check_EC_GROUP(NativeCrypto.EC_CURVE_GF2M, "sect283r1", "0800000000000000000000000000000000000000000000000000000000000000000010A1", "000000000000000000000000000000000000000000000000000000000000000000000001", "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", 2L); } private void check_EC_GROUP(int type, String name, String pStr, String aStr, String bStr, String xStr, String yStr, String nStr, long hLong) throws Exception { long group1 = NULL, group2 = NULL, point1 = NULL, point2 = NULL, key1 = NULL; try { group1 = NativeCrypto.EC_GROUP_new_by_curve_name(name); assertTrue(group1 != NULL); assertEquals(NativeCrypto.OBJ_txt2nid_longName(name), NativeCrypto.EC_GROUP_get_curve_name(group1)); assertEquals(type, NativeCrypto.get_EC_GROUP_type(group1)); // 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); group2 = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(), b.toByteArray()); assertEquals(type, NativeCrypto.get_EC_GROUP_type(group2)); point2 = NativeCrypto.EC_POINT_new(group2); NativeCrypto.EC_POINT_set_affine_coordinates(group2, point2, x.toByteArray(), y.toByteArray()); NativeCrypto.EC_GROUP_set_generator(group2, point2, n.toByteArray(), h.toByteArray()); point1 = NativeCrypto.EC_GROUP_get_generator(group2); assertTrue(NativeCrypto.EC_POINT_cmp(group1, point1, point2)); byte[][] pab = NativeCrypto.EC_GROUP_get_curve(group2); 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); byte[][] xy = NativeCrypto.EC_POINT_get_affine_coordinates(group2, point2); 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(group1)); assertEquals(n, n2); BigInteger h2 = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(group2)); assertEquals(h, h2); assertTrue(NativeCrypto.EC_GROUP_cmp(group1, group2)); key1 = NativeCrypto.EC_KEY_generate_key(group1); long groupTmp = NativeCrypto.EC_KEY_get0_group(key1); assertEquals(NativeCrypto.EC_GROUP_get_curve_name(group1), NativeCrypto.EC_GROUP_get_curve_name(groupTmp)); } finally { if (group1 != NULL) { NativeCrypto.EC_GROUP_clear_free(group1); } if (group2 != NULL) { NativeCrypto.EC_GROUP_clear_free(group2); } if (point1 != NULL) { NativeCrypto.EC_POINT_clear_free(point1); } if (point2 != NULL) { NativeCrypto.EC_POINT_clear_free(point2); } if (key1 != NULL) { NativeCrypto.EVP_PKEY_free(key1); } } } public void test_EC_KEY_get_private_key_null_key_Failure() throws Exception { try { NativeCrypto.EC_KEY_get_private_key(0); fail(); } catch (NullPointerException expected) {} } public void test_EC_KEY_get_public_key_null_key_Failure() throws Exception { try { NativeCrypto.EC_KEY_get_public_key(0); fail(); } catch (NullPointerException expected) {} } public void test_EC_KEY_set_nonce_from_hash_null_key_Failure() throws Exception { try { NativeCrypto.EC_KEY_set_nonce_from_hash(0, true); fail(); } catch (NullPointerException expected) {} } public void test_ECDH_compute_key_null_key_Failure() throws Exception { long groupRef = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); if (groupRef == 0) { fail(); } try { long pkey1Ref = NativeCrypto.EC_KEY_generate_key(groupRef); long pkey2Ref = NativeCrypto.EC_KEY_generate_key(groupRef); try { if (pkey1Ref == 0) { fail(); } if (pkey2Ref == 0) { fail(); } 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, 0, pkey2Ref); fail(); } catch (NullPointerException expected) {} // Assert that it fails when only the second key is null try { NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, 0); fail(); } catch (NullPointerException expected) {} } finally { NativeCrypto.EVP_PKEY_free(pkey1Ref); NativeCrypto.EVP_PKEY_free(pkey2Ref); } } finally { NativeCrypto.EC_GROUP_clear_free(groupRef); } } public void test_EVP_CipherInit_ex_Null_Failure() throws Exception { final long ctx = NativeCrypto.EVP_CIPHER_CTX_new(); try { final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); try { NativeCrypto.EVP_CipherInit_ex(NULL, evpCipher, null, null, true); fail("Null context should throw NullPointerException"); } catch (NullPointerException expected) { } /* 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); } finally { NativeCrypto.EVP_CIPHER_CTX_cleanup(ctx); } } public void test_EVP_CipherInit_ex_Success() throws Exception { final long ctx = NativeCrypto.EVP_CIPHER_CTX_new(); try { final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb"); NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, AES_128_KEY, null, true); } finally { NativeCrypto.EVP_CIPHER_CTX_cleanup(ctx); } } 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)); } 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); key1 = new OpenSSLKey(NativeCrypto.DSA_generate_key(1024, null, null, null, null)); assertTrue(key1.getPublicKey() instanceof DSAPublicKey); long group1 = NULL; try { group1 = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1"); assertTrue(group1 != NULL); key1 = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group1)); } finally { if (group1 != NULL) { NativeCrypto.EC_GROUP_clear_free(group1); } } assertTrue(key1.getPublicKey() instanceof ECPublicKey); } public void test_create_BIO_InputStream() throws Exception { byte[] actual = "Test".getBytes(); ByteArrayInputStream is = new ByteArrayInputStream(actual); @SuppressWarnings("resource") OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); 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(); } } public void test_create_BIO_OutputStream() throws Exception { byte[] actual = "Test".getBytes(); 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); } } private static void assertContains(String actualValue, String expectedSubstring) { if (actualValue == null) { return; } if (actualValue.contains(expectedSubstring)) { return; } fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\""); } }