1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt;
18
19import java.io.ByteArrayInputStream;
20import java.io.ByteArrayOutputStream;
21import java.io.FileDescriptor;
22import java.io.IOException;
23import java.io.UnsupportedEncodingException;
24import java.math.BigInteger;
25import java.net.ServerSocket;
26import java.net.Socket;
27import java.net.SocketException;
28import java.net.SocketTimeoutException;
29import java.security.KeyPair;
30import java.security.KeyPairGenerator;
31import java.security.KeyStore;
32import java.security.KeyStore.PrivateKeyEntry;
33import java.security.cert.Certificate;
34import java.security.cert.CertificateEncodingException;
35import java.security.cert.CertificateException;
36import java.security.cert.X509Certificate;
37import java.security.interfaces.ECPublicKey;
38import java.security.interfaces.RSAPrivateCrtKey;
39import java.security.interfaces.RSAPublicKey;
40import java.security.spec.ECPrivateKeySpec;
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.HashSet;
44import java.util.List;
45import java.util.concurrent.Callable;
46import java.util.concurrent.ExecutionException;
47import java.util.concurrent.ExecutorService;
48import java.util.concurrent.Executors;
49import java.util.concurrent.Future;
50import java.util.concurrent.TimeUnit;
51
52import javax.net.ssl.SSLException;
53import javax.net.ssl.SSLHandshakeException;
54import javax.net.ssl.SSLProtocolException;
55import javax.security.auth.x500.X500Principal;
56
57import junit.framework.TestCase;
58import libcore.io.IoUtils;
59import libcore.java.security.StandardNames;
60import libcore.java.security.TestKeyStore;
61
62import org.conscrypt.NativeCrypto.SSLHandshakeCallbacks;
63import static org.conscrypt.NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING;
64import static org.conscrypt.NativeConstants.SSL_MODE_HANDSHAKE_CUTTHROUGH;
65
66public class NativeCryptoTest extends TestCase {
67    /** Corresponds to the native test library "libjavacoretests.so" */
68    public static final String TEST_ENGINE_ID = "javacoretests";
69
70    private static final long NULL = 0;
71    private static final FileDescriptor INVALID_FD = new FileDescriptor();
72    private static final SSLHandshakeCallbacks DUMMY_CB
73            = new TestSSLHandshakeCallbacks(null, 0, null);
74
75    private static final long TIMEOUT_SECONDS = 5;
76
77    private static OpenSSLKey SERVER_PRIVATE_KEY;
78    private static OpenSSLX509Certificate[] SERVER_CERTIFICATES_HOLDER;
79    private static long[] SERVER_CERTIFICATES;
80    private static OpenSSLKey CLIENT_PRIVATE_KEY;
81    private static OpenSSLX509Certificate[] CLIENT_CERTIFICATES_HOLDER;
82    private static long[] CLIENT_CERTIFICATES;
83    private static byte[][] CA_PRINCIPALS;
84    private static OpenSSLKey CHANNEL_ID_PRIVATE_KEY;
85    private static byte[] CHANNEL_ID;
86
87    @Override
88    protected void tearDown() throws Exception {
89        assertEquals(0, NativeCrypto.ERR_peek_last_error());
90    }
91
92    private static OpenSSLKey getServerPrivateKey() {
93        initCerts();
94        return SERVER_PRIVATE_KEY;
95    }
96
97    private static long[] getServerCertificates() {
98        initCerts();
99        return SERVER_CERTIFICATES;
100    }
101
102    private static OpenSSLKey getClientPrivateKey() {
103        initCerts();
104        return CLIENT_PRIVATE_KEY;
105    }
106
107    private static long[] getClientCertificates() {
108        initCerts();
109        return CLIENT_CERTIFICATES;
110    }
111
112    private static byte[][] getCaPrincipals() {
113        initCerts();
114        return CA_PRINCIPALS;
115    }
116
117    /**
118     * Lazily create shared test certificates.
119     */
120    private static synchronized void initCerts() {
121        if (SERVER_PRIVATE_KEY != null) {
122            return;
123        }
124
125        try {
126            PrivateKeyEntry serverPrivateKeyEntry
127                    = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
128            SERVER_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(serverPrivateKeyEntry.getPrivateKey());
129            SERVER_CERTIFICATES_HOLDER = encodeCertificateList(
130                    serverPrivateKeyEntry.getCertificateChain());
131            SERVER_CERTIFICATES = getCertificateReferences(SERVER_CERTIFICATES_HOLDER);
132
133            PrivateKeyEntry clientPrivateKeyEntry
134                    = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA");
135            CLIENT_PRIVATE_KEY = OpenSSLKey.fromPrivateKey(clientPrivateKeyEntry.getPrivateKey());
136            CLIENT_CERTIFICATES_HOLDER = encodeCertificateList(
137                    clientPrivateKeyEntry.getCertificateChain());
138            CLIENT_CERTIFICATES = getCertificateReferences(CLIENT_CERTIFICATES_HOLDER);
139
140            KeyStore ks = TestKeyStore.getClient().keyStore;
141            String caCertAlias = ks.aliases().nextElement();
142            X509Certificate certificate = (X509Certificate) ks.getCertificate(caCertAlias);
143            X500Principal principal = certificate.getIssuerX500Principal();
144            CA_PRINCIPALS = new byte[][] { principal.getEncoded() };
145            initChannelIdKey();
146        } catch (Exception e) {
147            throw new RuntimeException(e);
148        }
149    }
150
151    private static long[] getCertificateReferences(OpenSSLX509Certificate[] certs) {
152        final long[] certRefs = new long[certs.length];
153        for (int i = 0; i < certs.length; i++) {
154            certRefs[i] = certs[i].getContext();
155        }
156        return certRefs;
157    }
158
159    private static OpenSSLX509Certificate[] encodeCertificateList(Certificate[] chain)
160            throws CertificateEncodingException {
161        final OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[chain.length];
162        for (int i = 0; i < chain.length; i++) {
163            openSslCerts[i] = OpenSSLX509Certificate.fromCertificate(chain[i]);
164        }
165        return openSslCerts;
166    }
167
168    private static synchronized void initChannelIdKey() throws Exception {
169        if (CHANNEL_ID_PRIVATE_KEY != null) {
170            return;
171        }
172
173        // NIST P-256 aka SECG secp256r1 aka X9.62 prime256v1
174        OpenSSLECGroupContext openSslSpec = OpenSSLECGroupContext.getCurveByName("prime256v1");
175        BigInteger s = new BigInteger(
176                "229cdbbf489aea584828a261a23f9ff8b0f66f7ccac98bf2096ab3aee41497c5", 16);
177        CHANNEL_ID_PRIVATE_KEY = new OpenSSLECPrivateKey(
178                new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec())).getOpenSSLKey();
179
180        // Channel ID is the concatenation of the X and Y coordinates of the public key.
181        CHANNEL_ID = new BigInteger(
182                "702b07871fd7955c320b26f15e244e47eed60272124c92b9ebecf0b42f90069b" +
183                        "ab53592ebfeb4f167dbf3ce61513afb0e354c479b1c1b69874fa471293494f77",
184                16).toByteArray();
185    }
186
187    public static void assertEqualSessions(long expected, long actual) {
188        assertEqualByteArrays(NativeCrypto.SSL_SESSION_session_id(expected),
189                              NativeCrypto.SSL_SESSION_session_id(actual));
190    }
191    public static void assertEqualByteArrays(byte[] expected, byte[] actual) {
192        assertEquals(Arrays.toString(expected), Arrays.toString(actual));
193    }
194
195    public static void assertEqualPrincipals(byte[][] expected, byte[][] actual) {
196        assertEqualByteArrays(expected, actual);
197    }
198
199    public static void assertEqualCertificateChains(long[] expected, long[] actual) {
200        assertEquals(expected.length, actual.length);
201        for (int i = 0; i < expected.length; i++) {
202            NativeCrypto.X509_cmp(expected[i], actual[i]);
203        }
204    }
205
206    public static void assertEqualByteArrays(byte[][] expected, byte[][] actual) {
207        assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual));
208    }
209
210    public void test_EVP_PKEY_cmp() throws Exception {
211        try {
212            NativeCrypto.EVP_PKEY_cmp(null, null);
213            fail("Should throw NullPointerException when arguments are NULL");
214        } catch (NullPointerException expected) {
215        }
216
217        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
218        kpg.initialize(512);
219
220        KeyPair kp1 = kpg.generateKeyPair();
221        RSAPrivateCrtKey privKey1 = (RSAPrivateCrtKey) kp1.getPrivate();
222
223        KeyPair kp2 = kpg.generateKeyPair();
224        RSAPrivateCrtKey privKey2 = (RSAPrivateCrtKey) kp2.getPrivate();
225
226        NativeRef.EVP_PKEY pkey1, pkey1_copy, pkey2;
227        pkey1 = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
228                privKey1.getModulus().toByteArray(),
229                privKey1.getPublicExponent().toByteArray(),
230                privKey1.getPrivateExponent().toByteArray(),
231                privKey1.getPrimeP().toByteArray(),
232                privKey1.getPrimeQ().toByteArray(),
233                privKey1.getPrimeExponentP().toByteArray(),
234                privKey1.getPrimeExponentQ().toByteArray(),
235                privKey1.getCrtCoefficient().toByteArray()));
236        assertNotSame(NULL, pkey1);
237
238        pkey1_copy = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
239                privKey1.getModulus().toByteArray(),
240                privKey1.getPublicExponent().toByteArray(),
241                privKey1.getPrivateExponent().toByteArray(),
242                privKey1.getPrimeP().toByteArray(),
243                privKey1.getPrimeQ().toByteArray(),
244                privKey1.getPrimeExponentP().toByteArray(),
245                privKey1.getPrimeExponentQ().toByteArray(),
246                privKey1.getCrtCoefficient().toByteArray()));
247        assertNotSame(NULL, pkey1_copy);
248
249        pkey2 = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
250                privKey2.getModulus().toByteArray(),
251                privKey2.getPublicExponent().toByteArray(),
252                privKey2.getPrivateExponent().toByteArray(),
253                privKey2.getPrimeP().toByteArray(),
254                privKey2.getPrimeQ().toByteArray(),
255                privKey2.getPrimeExponentP().toByteArray(),
256                privKey2.getPrimeExponentQ().toByteArray(),
257                privKey2.getCrtCoefficient().toByteArray()));
258        assertNotSame(NULL, pkey2);
259
260        try {
261            NativeCrypto.EVP_PKEY_cmp(pkey1, null);
262            fail("Should throw NullPointerException when arguments are NULL");
263        } catch (NullPointerException expected) {
264        }
265
266        try {
267            NativeCrypto.EVP_PKEY_cmp(null, null);
268            fail("Should throw NullPointerException when arguments are NULL");
269        } catch (NullPointerException expected) {
270        }
271
272        assertEquals("Same keys should be the equal", 1,
273                NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1));
274
275        assertEquals("Same keys should be the equal", 1,
276                NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1_copy));
277
278        assertEquals("Different keys should not be equal", 0,
279                NativeCrypto.EVP_PKEY_cmp(pkey1, pkey2));
280    }
281
282    public void test_SSL_CTX_new() throws Exception {
283        long c = NativeCrypto.SSL_CTX_new();
284        assertTrue(c != NULL);
285        long c2 = NativeCrypto.SSL_CTX_new();
286        assertTrue(c != c2);
287        NativeCrypto.SSL_CTX_free(c);
288        NativeCrypto.SSL_CTX_free(c2);
289    }
290
291    public void test_SSL_CTX_free() throws Exception {
292        try {
293            NativeCrypto.SSL_CTX_free(NULL);
294            fail();
295        } catch (NullPointerException expected) {
296        }
297
298        NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new());
299    }
300
301    public void test_SSL_CTX_set_session_id_context() throws Exception {
302        byte[] empty = new byte[0];
303        try {
304            NativeCrypto.SSL_CTX_set_session_id_context(NULL, empty);
305            fail();
306        } catch (NullPointerException expected) {
307        }
308        long c = NativeCrypto.SSL_CTX_new();
309        try {
310            NativeCrypto.SSL_CTX_set_session_id_context(c, null);
311            fail();
312        } catch (NullPointerException expected) {
313        }
314        NativeCrypto.SSL_CTX_set_session_id_context(c, empty);
315        NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[32]);
316        try {
317            NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]);
318        } catch (IllegalArgumentException expected) {
319        }
320        NativeCrypto.SSL_CTX_free(c);
321    }
322
323    public void test_SSL_new() throws Exception {
324        long c = NativeCrypto.SSL_CTX_new();
325        long s = NativeCrypto.SSL_new(c);
326
327        assertTrue(s != NULL);
328        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
329        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_TLSv1) == 0);
330        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_TLSv1_1) == 0);
331        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_TLSv1_2) == 0);
332
333        long s2 = NativeCrypto.SSL_new(c);
334        assertTrue(s != s2);
335        NativeCrypto.SSL_free(s2);
336
337        NativeCrypto.SSL_free(s);
338        NativeCrypto.SSL_CTX_free(c);
339    }
340
341    public void test_SSL_use_certificate() throws Exception {
342        try {
343            NativeCrypto.SSL_use_certificate(NULL, null);
344            fail();
345        } catch (NullPointerException expected) {
346        }
347
348        long c = NativeCrypto.SSL_CTX_new();
349        long s = NativeCrypto.SSL_new(c);
350
351        try {
352            NativeCrypto.SSL_use_certificate(s, null);
353            fail();
354        } catch (NullPointerException expected) {
355        }
356
357        NativeCrypto.SSL_use_certificate(s, getServerCertificates());
358
359        NativeCrypto.SSL_free(s);
360        NativeCrypto.SSL_CTX_free(c);
361    }
362
363    public void test_SSL_use_PrivateKey_for_tls_channel_id() throws Exception {
364        initChannelIdKey();
365
366        try {
367            NativeCrypto.SSL_set1_tls_channel_id(NULL, null);
368            fail();
369        } catch (NullPointerException expected) {
370        }
371
372        long c = NativeCrypto.SSL_CTX_new();
373        long s = NativeCrypto.SSL_new(c);
374
375        try {
376            NativeCrypto.SSL_set1_tls_channel_id(s, null);
377            fail();
378        } catch (NullPointerException expected) {
379        }
380
381        // Use the key natively. This works because the initChannelIdKey method ensures that the
382        // key is backed by OpenSSL.
383        NativeCrypto.SSL_set1_tls_channel_id(s, CHANNEL_ID_PRIVATE_KEY.getNativeRef());
384
385        NativeCrypto.SSL_free(s);
386        NativeCrypto.SSL_CTX_free(c);
387    }
388
389    public void test_SSL_use_PrivateKey() throws Exception {
390        try {
391            NativeCrypto.SSL_use_PrivateKey(NULL, null);
392            fail();
393        } catch (NullPointerException expected) {
394        }
395
396        long c = NativeCrypto.SSL_CTX_new();
397        long s = NativeCrypto.SSL_new(c);
398
399        try {
400            NativeCrypto.SSL_use_PrivateKey(s, null);
401            fail();
402        } catch (NullPointerException expected) {
403        }
404
405        NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
406
407        NativeCrypto.SSL_free(s);
408        NativeCrypto.SSL_CTX_free(c);
409    }
410
411    public void test_SSL_check_private_key_null() throws Exception {
412        try {
413            NativeCrypto.SSL_check_private_key(NULL);
414            fail();
415        } catch (NullPointerException expected) {
416        }
417    }
418
419    public void test_SSL_check_private_key_no_key_no_cert() throws Exception {
420        long c = NativeCrypto.SSL_CTX_new();
421        long s = NativeCrypto.SSL_new(c);
422
423        // neither private or certificate set
424        try {
425            NativeCrypto.SSL_check_private_key(s);
426            fail();
427        } catch (SSLException expected) {
428        }
429
430        NativeCrypto.SSL_free(s);
431        NativeCrypto.SSL_CTX_free(c);
432    }
433
434    public void test_SSL_check_private_key_cert_then_key() throws Exception {
435        long c = NativeCrypto.SSL_CTX_new();
436        long s = NativeCrypto.SSL_new(c);
437
438        // first certificate, then private
439        NativeCrypto.SSL_use_certificate(s, getServerCertificates());
440
441        try {
442            NativeCrypto.SSL_check_private_key(s);
443            fail();
444        } catch (SSLException expected) {
445        }
446
447        NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
448        NativeCrypto.SSL_check_private_key(s);
449
450        NativeCrypto.SSL_free(s);
451        NativeCrypto.SSL_CTX_free(c);
452    }
453    public void test_SSL_check_private_key_key_then_cert() throws Exception {
454        long c = NativeCrypto.SSL_CTX_new();
455        long s = NativeCrypto.SSL_new(c);
456
457        // first private, then certificate
458        NativeCrypto.SSL_use_PrivateKey(s, getServerPrivateKey().getNativeRef());
459
460        try {
461            NativeCrypto.SSL_check_private_key(s);
462            fail();
463        } catch (SSLException expected) {
464        }
465
466        NativeCrypto.SSL_use_certificate(s, getServerCertificates());
467        NativeCrypto.SSL_check_private_key(s);
468
469        NativeCrypto.SSL_free(s);
470        NativeCrypto.SSL_CTX_free(c);
471    }
472
473    public void test_SSL_get_mode() throws Exception {
474        try {
475            NativeCrypto.SSL_get_mode(NULL);
476            fail();
477        } catch (NullPointerException expected) {
478        }
479
480        long c = NativeCrypto.SSL_CTX_new();
481        long s = NativeCrypto.SSL_new(c);
482        assertTrue(NativeCrypto.SSL_get_mode(s) != 0);
483        NativeCrypto.SSL_free(s);
484        NativeCrypto.SSL_CTX_free(c);
485    }
486
487    public void test_SSL_set_mode_and_clear_mode() throws Exception {
488        try {
489            NativeCrypto.SSL_set_mode(NULL, 0);
490            fail();
491        } catch (NullPointerException expected) {
492        }
493
494        long c = NativeCrypto.SSL_CTX_new();
495        long s = NativeCrypto.SSL_new(c);
496        // check SSL_MODE_HANDSHAKE_CUTTHROUGH off by default
497        assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
498        // check SSL_MODE_CBC_RECORD_SPLITTING off by default
499        assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_CBC_RECORD_SPLITTING);
500
501        // set SSL_MODE_HANDSHAKE_CUTTHROUGH on
502        NativeCrypto.SSL_set_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
503        assertTrue((NativeCrypto.SSL_get_mode(s)
504                & SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0);
505        // clear SSL_MODE_HANDSHAKE_CUTTHROUGH off
506        NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
507        assertTrue((NativeCrypto.SSL_get_mode(s)
508                    & SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0);
509
510        NativeCrypto.SSL_free(s);
511        NativeCrypto.SSL_CTX_free(c);
512    }
513
514    public void test_SSL_get_options() throws Exception {
515        try {
516            NativeCrypto.SSL_get_options(NULL);
517            fail();
518        } catch (NullPointerException expected) {
519        }
520
521        long c = NativeCrypto.SSL_CTX_new();
522        long s = NativeCrypto.SSL_new(c);
523        assertTrue(NativeCrypto.SSL_get_options(s) != 0);
524        NativeCrypto.SSL_free(s);
525        NativeCrypto.SSL_CTX_free(c);
526    }
527
528    public void test_SSL_set_options() throws Exception {
529        try {
530            NativeCrypto.SSL_set_options(NULL, 0);
531            fail();
532        } catch (NullPointerException expected) {
533        }
534
535        long c = NativeCrypto.SSL_CTX_new();
536        long s = NativeCrypto.SSL_new(c);
537        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
538        NativeCrypto.SSL_set_options(s, NativeConstants.SSL_OP_NO_SSLv3);
539        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) != 0);
540        NativeCrypto.SSL_free(s);
541        NativeCrypto.SSL_CTX_free(c);
542    }
543
544    public void test_SSL_clear_options() throws Exception {
545        try {
546            NativeCrypto.SSL_clear_options(NULL, 0);
547            fail();
548        } catch (NullPointerException expected) {
549        }
550
551        long c = NativeCrypto.SSL_CTX_new();
552        long s = NativeCrypto.SSL_new(c);
553        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
554        NativeCrypto.SSL_set_options(s, NativeConstants.SSL_OP_NO_SSLv3);
555        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) != 0);
556        NativeCrypto.SSL_clear_options(s, NativeConstants.SSL_OP_NO_SSLv3);
557        assertTrue((NativeCrypto.SSL_get_options(s) & NativeConstants.SSL_OP_NO_SSLv3) == 0);
558        NativeCrypto.SSL_free(s);
559        NativeCrypto.SSL_CTX_free(c);
560    }
561
562    public void test_SSL_set_cipher_lists() throws Exception {
563        try {
564            NativeCrypto.SSL_set_cipher_lists(NULL, null);
565            fail("Exception not thrown for null ssl and null list");
566        } catch (NullPointerException expected) {
567        }
568
569        long c = NativeCrypto.SSL_CTX_new();
570        long s = NativeCrypto.SSL_new(c);
571
572        try {
573            NativeCrypto.SSL_set_cipher_lists(s, null);
574            fail("Exception not thrown for null list");
575        } catch (NullPointerException expected) {
576        }
577
578        // Explicitly checking that the empty list is allowed.
579        // b/21816861
580        NativeCrypto.SSL_set_cipher_lists(s, new String[]{});
581
582        try {
583            NativeCrypto.SSL_set_cipher_lists(s, new String[] { null });
584            fail("Exception not thrown for list with null element");
585        } catch (NullPointerException expected) {
586        }
587
588        // see OpenSSL ciphers man page
589        String[] illegals = new String[] {
590            // empty
591            "",
592            // never standardized
593            "EXP1024-DES-CBC-SHA", "EXP1024-RC4-SHA", "DHE-DSS-RC4-SHA",
594            // IDEA
595            "IDEA-CBC-SHA", "IDEA-CBC-MD5"
596        };
597
598        for (String illegal : illegals) {
599            try {
600                NativeCrypto.SSL_set_cipher_lists(s, new String[] { illegal });
601                fail("Exception now thrown for illegal cipher: " + illegal);
602            } catch (IllegalArgumentException expected) {
603            }
604        }
605
606        List<String> ciphers
607                = new ArrayList<String>(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.keySet());
608        NativeCrypto.SSL_set_cipher_lists(s, ciphers.toArray(new String[ciphers.size()]));
609
610        NativeCrypto.SSL_free(s);
611        NativeCrypto.SSL_CTX_free(c);
612    }
613
614    public void test_SSL_set_verify() throws Exception {
615        try {
616            NativeCrypto.SSL_set_verify(NULL, 0);
617            fail();
618        } catch (NullPointerException expected) {
619        }
620
621        long c = NativeCrypto.SSL_CTX_new();
622        long s = NativeCrypto.SSL_new(c);
623        NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_NONE);
624        NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER);
625        NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
626        NativeCrypto.SSL_set_verify(s, (NativeCrypto.SSL_VERIFY_PEER
627                                        | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT));
628        NativeCrypto.SSL_free(s);
629        NativeCrypto.SSL_CTX_free(c);
630    }
631
632    private static final boolean DEBUG = false;
633
634    public static class Hooks {
635        protected String negotiatedCipherSuite;
636        private OpenSSLKey channelIdPrivateKey;
637        protected boolean pskEnabled;
638        protected byte[] pskKey;
639        protected List<String> enabledCipherSuites;
640
641        /**
642         * @throws SSLException
643         */
644        public long getContext() throws SSLException {
645            return NativeCrypto.SSL_CTX_new();
646        }
647        public long beforeHandshake(long context) throws SSLException {
648            long s = NativeCrypto.SSL_new(context);
649            // without this SSL_set_cipher_lists call the tests were
650            // negotiating DHE-RSA-AES256-SHA by default which had
651            // very slow ephemeral RSA key generation
652            List<String> cipherSuites = new ArrayList<String>();
653            if (enabledCipherSuites == null) {
654                cipherSuites.add("RC4-MD5");
655                if (pskEnabled) {
656                    // In TLS-PSK the client indicates that PSK key exchange is desired by offering
657                    // at least one PSK cipher suite.
658                    cipherSuites.add(0, "PSK-AES128-CBC-SHA");
659                }
660            } else {
661                cipherSuites.addAll(enabledCipherSuites);
662            }
663            NativeCrypto.SSL_set_cipher_lists(
664                    s, cipherSuites.toArray(new String[cipherSuites.size()]));
665
666            if (channelIdPrivateKey != null) {
667                NativeCrypto.SSL_set1_tls_channel_id(s, channelIdPrivateKey.getNativeRef());
668            }
669            return s;
670        }
671        public void configureCallbacks(
672                @SuppressWarnings("unused") TestSSLHandshakeCallbacks callbacks) {}
673        public void clientCertificateRequested(@SuppressWarnings("unused") long s) {}
674        public void afterHandshake(long session, long ssl, long context,
675                                   Socket socket, FileDescriptor fd,
676                                   SSLHandshakeCallbacks callback)
677                throws Exception {
678            if (session != NULL) {
679                negotiatedCipherSuite = NativeCrypto.SSL_SESSION_cipher(session);
680                NativeCrypto.SSL_SESSION_free(session);
681            }
682            if (ssl != NULL) {
683                try {
684                    NativeCrypto.SSL_shutdown(ssl, fd, callback);
685                } catch (IOException e) {
686                }
687                NativeCrypto.SSL_free(ssl);
688            }
689            if (context != NULL) {
690                NativeCrypto.SSL_CTX_free(context);
691            }
692            if (socket != null) {
693                socket.close();
694            }
695        }
696    }
697
698    public static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks {
699        private final Socket socket;
700        private final long sslNativePointer;
701        private final Hooks hooks;
702
703        public TestSSLHandshakeCallbacks(Socket socket,
704                                         long sslNativePointer,
705                                         Hooks hooks) {
706            this.socket = socket;
707            this.sslNativePointer = sslNativePointer;
708            this.hooks = hooks;
709        }
710
711        public long[] certificateChainRefs;
712        public String authMethod;
713        public boolean verifyCertificateChainCalled;
714
715        @Override
716        public void verifyCertificateChain(long sslSessionNativePtr, long[] certChainRefs,
717                String authMethod) throws CertificateException {
718            if (DEBUG) {
719                System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
720                                   + " verifyCertificateChain"
721                                   + " sessionPtr=0x" + Long.toString(sslSessionNativePtr, 16)
722                                   + " asn1DerEncodedCertificateChain="
723                                   + Arrays.toString(certChainRefs)
724                                   + " authMethod=" + authMethod);
725            }
726            this.certificateChainRefs = certChainRefs;
727            this.authMethod = authMethod;
728            this.verifyCertificateChainCalled = true;
729        }
730
731        public byte[] keyTypes;
732        public byte[][] asn1DerEncodedX500Principals;
733        public boolean clientCertificateRequestedCalled;
734
735        @Override
736        public void clientCertificateRequested(byte[] keyTypes,
737                                               byte[][] asn1DerEncodedX500Principals) {
738            if (DEBUG) {
739                System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
740                                   + " clientCertificateRequested"
741                                   + " keyTypes=" + keyTypes
742                                   + " asn1DerEncodedX500Principals="
743                                   + asn1DerEncodedX500Principals);
744            }
745            this.keyTypes = keyTypes;
746            this.asn1DerEncodedX500Principals = asn1DerEncodedX500Principals;
747            this.clientCertificateRequestedCalled = true;
748            if (hooks != null ) {
749                hooks.clientCertificateRequested(sslNativePointer);
750            }
751        }
752
753        public boolean handshakeCompletedCalled;
754
755        @Override
756        public void onSSLStateChange(long sslSessionNativePtr, int type, int val) {
757            if (DEBUG) {
758                System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
759                                   + " onSSLStateChange");
760            }
761            this.handshakeCompletedCalled = true;
762        }
763
764        public Socket getSocket() {
765            return socket;
766        }
767
768        private boolean clientPSKKeyRequestedInvoked;
769        private String clientPSKKeyRequestedIdentityHint;
770        private int clientPSKKeyRequestedResult;
771        private byte[] clientPSKKeyRequestedResultKey;
772        private byte[] clientPSKKeyRequestedResultIdentity;
773
774        @Override
775        public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
776            if (DEBUG) {
777                System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
778                                   + " clientPSKKeyRequested"
779                                   + " identityHint=" + identityHint
780                                   + " identity capacity=" + identity.length
781                                   + " key capacity=" + key.length);
782            }
783            clientPSKKeyRequestedInvoked = true;
784            clientPSKKeyRequestedIdentityHint = identityHint;
785            if (clientPSKKeyRequestedResultKey != null) {
786                System.arraycopy(
787                        clientPSKKeyRequestedResultKey, 0,
788                        key, 0,
789                        clientPSKKeyRequestedResultKey.length);
790            }
791            if (clientPSKKeyRequestedResultIdentity != null) {
792                System.arraycopy(
793                        clientPSKKeyRequestedResultIdentity, 0,
794                        identity, 0,
795                        Math.min(clientPSKKeyRequestedResultIdentity.length, identity.length));
796            }
797            return clientPSKKeyRequestedResult;
798        }
799
800        private boolean serverPSKKeyRequestedInvoked;
801        private int serverPSKKeyRequestedResult;
802        private byte[] serverPSKKeyRequestedResultKey;
803        private String serverPSKKeyRequestedIdentityHint;
804        private String serverPSKKeyRequestedIdentity;
805        @Override
806        public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
807            if (DEBUG) {
808                System.out.println("ssl=0x" + Long.toString(sslNativePointer, 16)
809                                   + " serverPSKKeyRequested"
810                                   + " identityHint=" + identityHint
811                                   + " identity=" + identity
812                                   + " key capacity=" + key.length);
813            }
814            serverPSKKeyRequestedInvoked = true;
815            serverPSKKeyRequestedIdentityHint = identityHint;
816            serverPSKKeyRequestedIdentity = identity;
817            if (serverPSKKeyRequestedResultKey != null) {
818                System.arraycopy(
819                        serverPSKKeyRequestedResultKey, 0,
820                        key, 0,
821                        serverPSKKeyRequestedResultKey.length);
822            }
823            return serverPSKKeyRequestedResult;
824        }
825    }
826
827    public static class ClientHooks extends Hooks {
828        protected String pskIdentity;
829
830        @Override
831        public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
832            super.configureCallbacks(callbacks);
833            if (pskEnabled) {
834                if (pskIdentity != null) {
835                    // Create a NULL-terminated modified UTF-8 representation of pskIdentity.
836                    byte[] b;
837                    try {
838                        b = pskIdentity.getBytes("UTF-8");
839                    } catch (UnsupportedEncodingException e) {
840                        throw new RuntimeException("UTF-8 encoding not supported", e);
841                    }
842                    callbacks.clientPSKKeyRequestedResultIdentity =
843                            Arrays.copyOf(b, b.length + 1);
844                }
845                callbacks.clientPSKKeyRequestedResultKey = pskKey;
846                callbacks.clientPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0;
847            }
848        }
849
850        @Override
851        public long beforeHandshake(long c) throws SSLException {
852            long s = super.beforeHandshake(c);
853            if (pskEnabled) {
854                NativeCrypto.set_SSL_psk_client_callback_enabled(s, true);
855            }
856            return s;
857        }
858    }
859
860    public static class ServerHooks extends Hooks {
861        private final OpenSSLKey privateKey;
862        private final long[] certificates;
863        private boolean channelIdEnabled;
864        private byte[] channelIdAfterHandshake;
865        private Throwable channelIdAfterHandshakeException;
866
867        protected String pskIdentityHint;
868
869        public ServerHooks() {
870            this(null, null);
871        }
872
873        public ServerHooks(OpenSSLKey privateKey, long[] certificates) {
874            this.privateKey = privateKey;
875            this.certificates = certificates;
876        }
877
878        @Override
879        public long beforeHandshake(long c) throws SSLException {
880            long s = super.beforeHandshake(c);
881            if (privateKey != null) {
882                NativeCrypto.SSL_use_PrivateKey(s, privateKey.getNativeRef());
883            }
884            if (certificates != null) {
885                NativeCrypto.SSL_use_certificate(s, certificates);
886            }
887            if (channelIdEnabled) {
888                NativeCrypto.SSL_enable_tls_channel_id(s);
889            }
890            if (pskEnabled) {
891                NativeCrypto.set_SSL_psk_server_callback_enabled(s, true);
892                NativeCrypto.SSL_use_psk_identity_hint(s, pskIdentityHint);
893            }
894            NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_NONE);
895            return s;
896        }
897
898        @Override
899        public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
900            super.configureCallbacks(callbacks);
901            if (pskEnabled) {
902                callbacks.serverPSKKeyRequestedResultKey = pskKey;
903                callbacks.serverPSKKeyRequestedResult = (pskKey != null) ? pskKey.length : 0;
904            }
905        }
906
907        @Override
908        public void afterHandshake(long session, long ssl, long context,
909                                   Socket socket, FileDescriptor fd,
910                                   SSLHandshakeCallbacks callback)
911                throws Exception {
912          if (channelIdEnabled) {
913            try {
914              channelIdAfterHandshake = NativeCrypto.SSL_get_tls_channel_id(ssl);
915            } catch (Exception e) {
916              channelIdAfterHandshakeException = e;
917            }
918          }
919          super.afterHandshake(session, ssl, context, socket, fd, callback);
920        }
921
922        @Override
923        public void clientCertificateRequested(long s) {
924            fail("Server asked for client certificates");
925        }
926    }
927
928    public static Future<TestSSLHandshakeCallbacks> handshake(final ServerSocket listener,
929            final int timeout, final boolean client, final Hooks hooks, final byte[] npnProtocols,
930            final byte[] alpnProtocols) {
931        ExecutorService executor = Executors.newSingleThreadExecutor();
932        Future<TestSSLHandshakeCallbacks> future = executor.submit(
933                new Callable<TestSSLHandshakeCallbacks>() {
934            @Override public TestSSLHandshakeCallbacks call() throws Exception {
935                @SuppressWarnings("resource") // Socket needs to remain open after the handshake
936                Socket socket = (client
937                                 ? new Socket(listener.getInetAddress(),
938                                              listener.getLocalPort())
939                                 : listener.accept());
940                if (timeout == -1) {
941                    return new TestSSLHandshakeCallbacks(socket, 0, null);
942                }
943                FileDescriptor fd = socket.getFileDescriptor$();
944                long c = hooks.getContext();
945                long s = hooks.beforeHandshake(c);
946                TestSSLHandshakeCallbacks callback
947                        = new TestSSLHandshakeCallbacks(socket, s, hooks);
948                hooks.configureCallbacks(callback);
949                if (DEBUG) {
950                    System.out.println("ssl=0x" + Long.toString(s, 16)
951                                       + " handshake"
952                                       + " context=0x" + Long.toString(c, 16)
953                                       + " socket=" + socket
954                                       + " fd=" + fd
955                                       + " timeout=" + timeout
956                                       + " client=" + client);
957                }
958                long session = NULL;
959                try {
960                    session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client,
961                                                            npnProtocols, alpnProtocols);
962                    if (DEBUG) {
963                        System.out.println("ssl=0x" + Long.toString(s, 16)
964                                           + " handshake"
965                                           + " session=0x" + Long.toString(session, 16));
966                    }
967                } finally {
968                    // Ensure afterHandshake is called to free resources
969                    hooks.afterHandshake(session, s, c, socket, fd, callback);
970                }
971                return callback;
972            }
973        });
974        executor.shutdown();
975        return future;
976    }
977
978    public void test_SSL_do_handshake_NULL_SSL() throws Exception {
979        try {
980            NativeCrypto.SSL_do_handshake(NULL, null, null, 0, false, null, null);
981            fail();
982        } catch (NullPointerException expected) {
983        }
984    }
985
986    public void test_SSL_do_handshake_null_args() throws Exception {
987        long c = NativeCrypto.SSL_CTX_new();
988        long s = NativeCrypto.SSL_new(c);
989
990        try {
991            NativeCrypto.SSL_do_handshake(s, null, null, 0, true, null, null);
992            fail();
993        } catch (NullPointerException expected) {
994        }
995
996        try {
997            NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0, true, null, null);
998            fail();
999        } catch (NullPointerException expected) {
1000        }
1001
1002        NativeCrypto.SSL_free(s);
1003        NativeCrypto.SSL_CTX_free(c);
1004    }
1005
1006    public void test_SSL_do_handshake_normal() throws Exception {
1007        // normal client and server case
1008        final ServerSocket listener = new ServerSocket(0);
1009        Hooks cHooks = new Hooks();
1010        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1011        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1012        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1013        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1014        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1015        assertTrue(clientCallback.verifyCertificateChainCalled);
1016        assertEqualCertificateChains(getServerCertificates(),
1017                                     clientCallback.certificateChainRefs);
1018        assertEquals("RSA", clientCallback.authMethod);
1019        assertFalse(serverCallback.verifyCertificateChainCalled);
1020        assertFalse(clientCallback.clientCertificateRequestedCalled);
1021        assertFalse(serverCallback.clientCertificateRequestedCalled);
1022        assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
1023        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1024        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1025        assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
1026        assertTrue(clientCallback.handshakeCompletedCalled);
1027        assertTrue(serverCallback.handshakeCompletedCalled);
1028    }
1029
1030    public void test_SSL_do_handshake_optional_client_certificate() throws Exception {
1031        // optional client certificate case
1032        final ServerSocket listener = new ServerSocket(0);
1033
1034        Hooks cHooks = new Hooks() {
1035            @Override
1036            public void clientCertificateRequested(long s) {
1037                super.clientCertificateRequested(s);
1038                NativeCrypto.SSL_use_PrivateKey(s, getClientPrivateKey().getNativeRef());
1039                NativeCrypto.SSL_use_certificate(s, getClientCertificates());
1040            }
1041        };
1042        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1043            @Override
1044            public long beforeHandshake(long c) throws SSLException {
1045                long s = super.beforeHandshake(c);
1046                NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals());
1047                NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER);
1048                return s;
1049            }
1050        };
1051        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1052        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1053        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1054        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1055        assertTrue(clientCallback.verifyCertificateChainCalled);
1056        assertEqualCertificateChains(getServerCertificates(),
1057                                     clientCallback.certificateChainRefs);
1058        assertEquals("RSA", clientCallback.authMethod);
1059        assertTrue(serverCallback.verifyCertificateChainCalled);
1060        assertEqualCertificateChains(getClientCertificates(),
1061                serverCallback.certificateChainRefs);
1062        assertEquals("RSA", serverCallback.authMethod);
1063
1064        assertTrue(clientCallback.clientCertificateRequestedCalled);
1065        assertNotNull(clientCallback.keyTypes);
1066        assertEquals(new HashSet<String>(Arrays.asList("EC", "RSA")),
1067                SSLParametersImpl.getSupportedClientKeyTypes(clientCallback.keyTypes));
1068        assertEqualPrincipals(getCaPrincipals(),
1069                              clientCallback.asn1DerEncodedX500Principals);
1070        assertFalse(serverCallback.clientCertificateRequestedCalled);
1071
1072        assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
1073        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1074        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1075        assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
1076
1077        assertTrue(clientCallback.handshakeCompletedCalled);
1078        assertTrue(serverCallback.handshakeCompletedCalled);
1079    }
1080
1081    public void test_SSL_do_handshake_missing_required_certificate() throws Exception {
1082        // required client certificate negative case
1083        final ServerSocket listener = new ServerSocket(0);
1084        try {
1085            Hooks cHooks = new Hooks();
1086            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1087                @Override
1088                public long beforeHandshake(long c) throws SSLException {
1089                    long s = super.beforeHandshake(c);
1090                    NativeCrypto.SSL_set_client_CA_list(s, getCaPrincipals());
1091                    NativeCrypto.SSL_set_verify(s,
1092                                                NativeCrypto.SSL_VERIFY_PEER
1093                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
1094                    return s;
1095                }
1096            };
1097            @SuppressWarnings("unused")
1098            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
1099                    null);
1100            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
1101                    null);
1102            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1103            fail();
1104        } catch (ExecutionException expected) {
1105            assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1106        }
1107    }
1108
1109    /**
1110     * Usually if a RuntimeException is thrown by the
1111     * clientCertificateRequestedCalled callback, the caller sees it
1112     * during the call to NativeCrypto_SSL_do_handshake.  However, IIS
1113     * does not request client certs until after the initial
1114     * handshake. It does an SSL renegotiation, which means we need to
1115     * be able to deliver the callback's exception in cases like
1116     * SSL_read, SSL_write, and SSL_shutdown.
1117     */
1118    public void test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate()
1119            throws Exception {
1120        final ServerSocket listener = new ServerSocket(0);
1121
1122        Hooks cHooks = new Hooks() {
1123            @Override
1124            public long beforeHandshake(long context) throws SSLException {
1125                long s = super.beforeHandshake(context);
1126                NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
1127                return s;
1128            }
1129            @Override
1130            public void afterHandshake(long session, long s, long c,
1131                                       Socket sock, FileDescriptor fd,
1132                                       SSLHandshakeCallbacks callback)
1133                    throws Exception {
1134                NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0);
1135                fail();
1136                super.afterHandshake(session, s, c, sock, fd, callback);
1137            }
1138            @Override
1139            public void clientCertificateRequested(long s) {
1140                super.clientCertificateRequested(s);
1141                throw new RuntimeException("expected");
1142            }
1143        };
1144        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1145            @Override
1146            public void afterHandshake(long session, long s, long c,
1147                                       Socket sock, FileDescriptor fd,
1148                                       SSLHandshakeCallbacks callback)
1149                    throws Exception {
1150                try {
1151                    NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER);
1152                    NativeCrypto.SSL_set_options(
1153                            s, NativeConstants.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
1154                    NativeCrypto.SSL_renegotiate(s);
1155                    NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1,
1156                                           (int) ((TIMEOUT_SECONDS * 1000) / 2));
1157                } catch (IOException expected) {
1158                } finally {
1159                    super.afterHandshake(session, s, c, sock, fd, callback);
1160                }
1161            }
1162        };
1163        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1164        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1165        try {
1166            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1167        } catch (ExecutionException e) {
1168            if (!"expected".equals(e.getCause().getMessage())) {
1169                throw e;
1170            }
1171        }
1172        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1173    }
1174
1175    public void test_SSL_do_handshake_client_timeout() throws Exception {
1176        // client timeout
1177        final ServerSocket listener = new ServerSocket(0);
1178        Socket serverSocket = null;
1179        try {
1180            Hooks cHooks = new Hooks();
1181            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1182            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 1, true, cHooks, null,
1183                    null);
1184            Future<TestSSLHandshakeCallbacks> server = handshake(listener, -1, false, sHooks, null,
1185                    null);
1186            serverSocket = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket();
1187            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1188            fail();
1189        } catch (ExecutionException expected) {
1190            if (SocketTimeoutException.class != expected.getCause().getClass()) {
1191                expected.printStackTrace();
1192            }
1193            assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
1194        } finally {
1195            // Manually close peer socket when testing timeout
1196            IoUtils.closeQuietly(serverSocket);
1197        }
1198    }
1199
1200    public void test_SSL_do_handshake_server_timeout() throws Exception {
1201        // server timeout
1202        final ServerSocket listener = new ServerSocket(0);
1203        Socket clientSocket = null;
1204        try {
1205            Hooks cHooks = new Hooks();
1206            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1207            Future<TestSSLHandshakeCallbacks> client = handshake(listener, -1, true, cHooks, null, null);
1208            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 1, false, sHooks, null, null);
1209            clientSocket = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket();
1210            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1211            fail();
1212        } catch (ExecutionException expected) {
1213            assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
1214        } finally {
1215            // Manually close peer socket when testing timeout
1216            IoUtils.closeQuietly(clientSocket);
1217        }
1218    }
1219
1220    public void test_SSL_do_handshake_with_channel_id_normal() throws Exception {
1221        initChannelIdKey();
1222
1223        // Normal handshake with TLS Channel ID.
1224        final ServerSocket listener = new ServerSocket(0);
1225        Hooks cHooks = new Hooks();
1226        cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
1227        // TLS Channel ID currently requires ECDHE-based key exchanges.
1228        cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
1229        ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1230        sHooks.channelIdEnabled = true;
1231        sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
1232        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1233        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1234        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1235        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1236        assertTrue(clientCallback.verifyCertificateChainCalled);
1237        assertEqualCertificateChains(getServerCertificates(),
1238                                     clientCallback.certificateChainRefs);
1239        assertEquals("ECDHE_RSA", clientCallback.authMethod);
1240        assertFalse(serverCallback.verifyCertificateChainCalled);
1241        assertFalse(clientCallback.clientCertificateRequestedCalled);
1242        assertFalse(serverCallback.clientCertificateRequestedCalled);
1243        assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
1244        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1245        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1246        assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
1247        assertTrue(clientCallback.handshakeCompletedCalled);
1248        assertTrue(serverCallback.handshakeCompletedCalled);
1249        assertNull(sHooks.channelIdAfterHandshakeException);
1250        assertEqualByteArrays(CHANNEL_ID, sHooks.channelIdAfterHandshake);
1251    }
1252
1253    public void test_SSL_do_handshake_with_channel_id_not_supported_by_server() throws Exception {
1254        initChannelIdKey();
1255
1256        // Client tries to use TLS Channel ID but the server does not enable/offer the extension.
1257        final ServerSocket listener = new ServerSocket(0);
1258        Hooks cHooks = new Hooks();
1259        cHooks.channelIdPrivateKey = CHANNEL_ID_PRIVATE_KEY;
1260        // TLS Channel ID currently requires ECDHE-based key exchanges.
1261        cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
1262        ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1263        sHooks.channelIdEnabled = false;
1264        sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
1265        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1266        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1267        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1268        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1269        assertTrue(clientCallback.verifyCertificateChainCalled);
1270        assertEqualCertificateChains(getServerCertificates(),
1271                                     clientCallback.certificateChainRefs);
1272        assertEquals("ECDHE_RSA", clientCallback.authMethod);
1273        assertFalse(serverCallback.verifyCertificateChainCalled);
1274        assertFalse(clientCallback.clientCertificateRequestedCalled);
1275        assertFalse(serverCallback.clientCertificateRequestedCalled);
1276        assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
1277        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1278        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1279        assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
1280        assertTrue(clientCallback.handshakeCompletedCalled);
1281        assertTrue(serverCallback.handshakeCompletedCalled);
1282        assertNull(sHooks.channelIdAfterHandshakeException);
1283        assertNull(sHooks.channelIdAfterHandshake);
1284    }
1285
1286    public void test_SSL_do_handshake_with_channel_id_not_enabled_by_client() throws Exception {
1287        initChannelIdKey();
1288
1289        // Client does not use TLS Channel ID when the server has the extension enabled/offered.
1290        final ServerSocket listener = new ServerSocket(0);
1291        Hooks cHooks = new Hooks();
1292        cHooks.channelIdPrivateKey = null;
1293        // TLS Channel ID currently requires ECDHE-based key exchanges.
1294        cHooks.enabledCipherSuites = Arrays.asList(new String[] {"ECDHE-RSA-AES128-SHA"});
1295        ServerHooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1296        sHooks.channelIdEnabled = true;
1297        sHooks.enabledCipherSuites = cHooks.enabledCipherSuites;
1298        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1299        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1300        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1301        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1302        assertTrue(clientCallback.verifyCertificateChainCalled);
1303        assertEqualCertificateChains(getServerCertificates(),
1304                                     clientCallback.certificateChainRefs);
1305        assertEquals("ECDHE_RSA", clientCallback.authMethod);
1306        assertFalse(serverCallback.verifyCertificateChainCalled);
1307        assertFalse(clientCallback.clientCertificateRequestedCalled);
1308        assertFalse(serverCallback.clientCertificateRequestedCalled);
1309        assertFalse(clientCallback.clientPSKKeyRequestedInvoked);
1310        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1311        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1312        assertFalse(serverCallback.serverPSKKeyRequestedInvoked);
1313        assertTrue(clientCallback.handshakeCompletedCalled);
1314        assertTrue(serverCallback.handshakeCompletedCalled);
1315        assertNull(sHooks.channelIdAfterHandshakeException);
1316        assertNull(sHooks.channelIdAfterHandshake);
1317    }
1318
1319    public void test_SSL_do_handshake_with_psk_normal() throws Exception {
1320        // normal TLS-PSK client and server case
1321        final ServerSocket listener = new ServerSocket(0);
1322        Hooks cHooks = new ClientHooks();
1323        ServerHooks sHooks = new ServerHooks();
1324        cHooks.pskEnabled = true;
1325        sHooks.pskEnabled = true;
1326        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1327        sHooks.pskKey = cHooks.pskKey;
1328        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1329        Future<TestSSLHandshakeCallbacks> server =
1330                handshake(listener, 0, false, sHooks, null, null);
1331        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1332        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1333        assertFalse(clientCallback.verifyCertificateChainCalled);
1334        assertFalse(serverCallback.verifyCertificateChainCalled);
1335        assertFalse(clientCallback.clientCertificateRequestedCalled);
1336        assertFalse(serverCallback.clientCertificateRequestedCalled);
1337        assertTrue(clientCallback.handshakeCompletedCalled);
1338        assertTrue(serverCallback.handshakeCompletedCalled);
1339        assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
1340        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1341        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1342        assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
1343        assertContains(cHooks.negotiatedCipherSuite, "PSK");
1344        assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
1345        assertNull(clientCallback.clientPSKKeyRequestedIdentityHint);
1346        assertNull(serverCallback.serverPSKKeyRequestedIdentityHint);
1347        assertEquals("", serverCallback.serverPSKKeyRequestedIdentity);
1348    }
1349
1350    public void test_SSL_do_handshake_with_psk_with_identity_and_hint() throws Exception {
1351        // normal TLS-PSK client and server case where the server provides the client with a PSK
1352        // identity hint, and the client provides the server with a PSK identity.
1353        final ServerSocket listener = new ServerSocket(0);
1354        ClientHooks cHooks = new ClientHooks();
1355        ServerHooks sHooks = new ServerHooks();
1356        cHooks.pskEnabled = true;
1357        sHooks.pskEnabled = true;
1358        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1359        sHooks.pskKey = cHooks.pskKey;
1360        sHooks.pskIdentityHint = "Some non-ASCII characters: \u00c4\u0332";
1361        cHooks.pskIdentity = "More non-ASCII characters: \u00f5\u044b";
1362        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1363        Future<TestSSLHandshakeCallbacks> server =
1364                handshake(listener, 0, false, sHooks, null, null);
1365        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1366        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1367        assertFalse(clientCallback.verifyCertificateChainCalled);
1368        assertFalse(serverCallback.verifyCertificateChainCalled);
1369        assertFalse(clientCallback.clientCertificateRequestedCalled);
1370        assertFalse(serverCallback.clientCertificateRequestedCalled);
1371        assertTrue(clientCallback.handshakeCompletedCalled);
1372        assertTrue(serverCallback.handshakeCompletedCalled);
1373        assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
1374        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1375        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1376        assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
1377        assertContains(cHooks.negotiatedCipherSuite, "PSK");
1378        assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
1379        assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint);
1380        assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint);
1381        assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity);
1382    }
1383
1384    public void test_SSL_do_handshake_with_psk_with_identity_and_hint_of_max_length()
1385            throws Exception {
1386        // normal TLS-PSK client and server case where the server provides the client with a PSK
1387        // identity hint, and the client provides the server with a PSK identity.
1388        final ServerSocket listener = new ServerSocket(0);
1389        ClientHooks cHooks = new ClientHooks();
1390        ServerHooks sHooks = new ServerHooks();
1391        cHooks.pskEnabled = true;
1392        sHooks.pskEnabled = true;
1393        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1394        sHooks.pskKey = cHooks.pskKey;
1395        sHooks.pskIdentityHint = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
1396                + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx";
1397        cHooks.pskIdentity = "123456789012345678901234567890123456789012345678901234567890"
1398                + "12345678901234567890123456789012345678901234567890123456789012345678";
1399        assertEquals(PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES, sHooks.pskIdentityHint.length());
1400        assertEquals(PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES, cHooks.pskIdentity.length());
1401        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1402        Future<TestSSLHandshakeCallbacks> server =
1403                handshake(listener, 0, false, sHooks, null, null);
1404        TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1405        TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1406        assertFalse(clientCallback.verifyCertificateChainCalled);
1407        assertFalse(serverCallback.verifyCertificateChainCalled);
1408        assertFalse(clientCallback.clientCertificateRequestedCalled);
1409        assertFalse(serverCallback.clientCertificateRequestedCalled);
1410        assertTrue(clientCallback.handshakeCompletedCalled);
1411        assertTrue(serverCallback.handshakeCompletedCalled);
1412        assertTrue(clientCallback.clientPSKKeyRequestedInvoked);
1413        assertFalse(clientCallback.serverPSKKeyRequestedInvoked);
1414        assertFalse(serverCallback.clientPSKKeyRequestedInvoked);
1415        assertTrue(serverCallback.serverPSKKeyRequestedInvoked);
1416        assertContains(cHooks.negotiatedCipherSuite, "PSK");
1417        assertEquals(cHooks.negotiatedCipherSuite, sHooks.negotiatedCipherSuite);
1418        assertEquals(sHooks.pskIdentityHint, clientCallback.clientPSKKeyRequestedIdentityHint);
1419        assertEquals(sHooks.pskIdentityHint, serverCallback.serverPSKKeyRequestedIdentityHint);
1420        assertEquals(cHooks.pskIdentity, serverCallback.serverPSKKeyRequestedIdentity);
1421    }
1422
1423    public void test_SSL_do_handshake_with_psk_key_mismatch() throws Exception {
1424        final ServerSocket listener = new ServerSocket(0);
1425        ClientHooks cHooks = new ClientHooks();
1426        ServerHooks sHooks = new ServerHooks();
1427        cHooks.pskEnabled = true;
1428        sHooks.pskEnabled = true;
1429        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1430        sHooks.pskKey = "1, 2, 3, 3, Testing...".getBytes("UTF-8");
1431        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1432        Future<TestSSLHandshakeCallbacks> server =
1433                handshake(listener, 0, false, sHooks, null, null);
1434        try {
1435            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1436            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1437            fail();
1438        } catch (ExecutionException expected) {
1439            assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1440        }
1441    }
1442
1443    public void test_SSL_do_handshake_with_psk_with_no_client_key() throws Exception {
1444        final ServerSocket listener = new ServerSocket(0);
1445        ClientHooks cHooks = new ClientHooks();
1446        ServerHooks sHooks = new ServerHooks();
1447        cHooks.pskEnabled = true;
1448        sHooks.pskEnabled = true;
1449        cHooks.pskKey = null;
1450        sHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1451        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1452        Future<TestSSLHandshakeCallbacks> server =
1453                handshake(listener, 0, false, sHooks, null, null);
1454        try {
1455            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1456            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1457            fail();
1458        } catch (ExecutionException expected) {
1459            assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1460        }
1461    }
1462
1463    public void test_SSL_do_handshake_with_psk_with_no_server_key() throws Exception {
1464        final ServerSocket listener = new ServerSocket(0);
1465        ClientHooks cHooks = new ClientHooks();
1466        ServerHooks sHooks = new ServerHooks();
1467        cHooks.pskEnabled = true;
1468        sHooks.pskEnabled = true;
1469        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1470        sHooks.pskKey = null;
1471        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1472        Future<TestSSLHandshakeCallbacks> server =
1473                handshake(listener, 0, false, sHooks, null, null);
1474        try {
1475            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1476            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1477            fail();
1478        } catch (ExecutionException expected) {
1479            assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1480        }
1481    }
1482
1483    public void test_SSL_do_handshake_with_psk_key_too_long() throws Exception {
1484        final ServerSocket listener = new ServerSocket(0);
1485        ClientHooks cHooks = new ClientHooks() {
1486            @Override
1487            public void configureCallbacks(TestSSLHandshakeCallbacks callbacks) {
1488                super.configureCallbacks(callbacks);
1489                callbacks.clientPSKKeyRequestedResult = PSKKeyManager.MAX_KEY_LENGTH_BYTES + 1;
1490            }
1491        };
1492        ServerHooks sHooks = new ServerHooks();
1493        cHooks.pskEnabled = true;
1494        sHooks.pskEnabled = true;
1495        cHooks.pskKey = "1, 2, 3, 4, Testing...".getBytes("UTF-8");
1496        sHooks.pskKey = cHooks.pskKey;
1497        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1498        Future<TestSSLHandshakeCallbacks> server =
1499                handshake(listener, 0, false, sHooks, null, null);
1500        try {
1501            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1502            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1503            fail();
1504        } catch (ExecutionException expected) {
1505            assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1506        }
1507    }
1508
1509    public void test_SSL_use_psk_identity_hint() throws Exception {
1510        long c = NativeCrypto.SSL_CTX_new();
1511        long s = NativeCrypto.SSL_new(c);
1512        try {
1513            NativeCrypto.SSL_use_psk_identity_hint(s, null);
1514            NativeCrypto.SSL_use_psk_identity_hint(s, "test");
1515
1516            try {
1517                // 800 characters is much longer than the permitted maximum.
1518                StringBuilder pskIdentityHint = new StringBuilder();
1519                for (int i = 0; i < 160; i++) {
1520                    pskIdentityHint.append(" long");
1521                }
1522                assertTrue(pskIdentityHint.length() > PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES);
1523                NativeCrypto.SSL_use_psk_identity_hint(s, pskIdentityHint.toString());
1524                fail();
1525            } catch (SSLException expected) {
1526            }
1527        } finally {
1528            NativeCrypto.SSL_free(s);
1529            NativeCrypto.SSL_CTX_free(c);
1530        }
1531    }
1532
1533    public void test_SSL_set_session() throws Exception {
1534        try {
1535            NativeCrypto.SSL_set_session(NULL, NULL);
1536            fail();
1537        } catch (NullPointerException expected) {
1538        }
1539
1540        {
1541            long c = NativeCrypto.SSL_CTX_new();
1542            long s = NativeCrypto.SSL_new(c);
1543            NativeCrypto.SSL_set_session(s, NULL);
1544            NativeCrypto.SSL_free(s);
1545            NativeCrypto.SSL_CTX_free(c);
1546        }
1547
1548        {
1549            final long clientContext = NativeCrypto.SSL_CTX_new();
1550            final long serverContext = NativeCrypto.SSL_CTX_new();
1551            final ServerSocket listener = new ServerSocket(0);
1552            final long[] clientSession = new long[] { NULL };
1553            final long[] serverSession = new long[] { NULL };
1554            {
1555                Hooks cHooks = new Hooks() {
1556                    @Override
1557                    public long getContext() throws SSLException {
1558                        return clientContext;
1559                    }
1560                    @Override
1561                    public void afterHandshake(long session, long s, long c,
1562                                               Socket sock, FileDescriptor fd,
1563                                               SSLHandshakeCallbacks callback)
1564                            throws Exception {
1565                        super.afterHandshake(NULL, s, NULL, sock, fd, callback);
1566                        clientSession[0] = session;
1567                    }
1568                };
1569                Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1570                    @Override
1571                    public long getContext() throws SSLException {
1572                        return serverContext;
1573                    }
1574                    @Override
1575                    public void afterHandshake(long session, long s, long c,
1576                                               Socket sock, FileDescriptor fd,
1577                                               SSLHandshakeCallbacks callback)
1578                            throws Exception {
1579                        super.afterHandshake(NULL, s, NULL, sock, fd, callback);
1580                        serverSession[0] = session;
1581                    }
1582                };
1583                Future<TestSSLHandshakeCallbacks> client
1584                        = handshake(listener, 0, true, cHooks, null, null);
1585                Future<TestSSLHandshakeCallbacks> server
1586                        = handshake(listener, 0, false, sHooks, null, null);
1587                client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1588                server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1589            }
1590            assertEqualSessions(clientSession[0], serverSession[0]);
1591            {
1592                Hooks cHooks = new Hooks() {
1593                    @Override
1594                    public long getContext() throws SSLException {
1595                        return clientContext;
1596                    }
1597                    @Override
1598                    public long beforeHandshake(long c) throws SSLException {
1599                        long s = NativeCrypto.SSL_new(clientContext);
1600                        NativeCrypto.SSL_set_session(s, clientSession[0]);
1601                        return s;
1602                    }
1603                    @Override
1604                    public void afterHandshake(long session, long s, long c,
1605                                               Socket sock, FileDescriptor fd,
1606                                               SSLHandshakeCallbacks callback)
1607                            throws Exception {
1608                        assertEqualSessions(clientSession[0], session);
1609                        super.afterHandshake(NULL, s, NULL, sock, fd, callback);
1610                    }
1611                };
1612                Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1613                    @Override
1614                    public long getContext() throws SSLException {
1615                        return serverContext;
1616                    }
1617                    @Override
1618                    public void afterHandshake(long session, long s, long c,
1619                                               Socket sock, FileDescriptor fd,
1620                                               SSLHandshakeCallbacks callback)
1621                            throws Exception {
1622                        assertEqualSessions(serverSession[0], session);
1623                        super.afterHandshake(NULL, s, NULL, sock, fd, callback);
1624                    }
1625                };
1626                Future<TestSSLHandshakeCallbacks> client
1627                        = handshake(listener, 0, true, cHooks, null, null);
1628                Future<TestSSLHandshakeCallbacks> server
1629                        = handshake(listener, 0, false, sHooks, null, null);
1630                client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1631                server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1632            }
1633            NativeCrypto.SSL_SESSION_free(clientSession[0]);
1634            NativeCrypto.SSL_SESSION_free(serverSession[0]);
1635            NativeCrypto.SSL_CTX_free(serverContext);
1636            NativeCrypto.SSL_CTX_free(clientContext);
1637        }
1638    }
1639
1640    public void test_SSL_set_session_creation_enabled() throws Exception {
1641        try {
1642            NativeCrypto.SSL_set_session_creation_enabled(NULL, false);
1643            fail();
1644        } catch (NullPointerException expected) {
1645        }
1646
1647        {
1648            long c = NativeCrypto.SSL_CTX_new();
1649            long s = NativeCrypto.SSL_new(c);
1650            NativeCrypto.SSL_set_session_creation_enabled(s, false);
1651            NativeCrypto.SSL_set_session_creation_enabled(s, true);
1652            NativeCrypto.SSL_free(s);
1653            NativeCrypto.SSL_CTX_free(c);
1654        }
1655
1656        final ServerSocket listener = new ServerSocket(0);
1657
1658        // negative test case for SSL_set_session_creation_enabled(false) on client
1659        {
1660            Hooks cHooks = new Hooks() {
1661                @Override
1662                public long beforeHandshake(long c) throws SSLException {
1663                    long s = super.beforeHandshake(c);
1664                    NativeCrypto.SSL_set_session_creation_enabled(s, false);
1665                    return s;
1666                }
1667            };
1668            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
1669            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
1670                    null);
1671            @SuppressWarnings("unused")
1672            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
1673                    null);
1674            try {
1675                client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1676                fail();
1677            } catch (ExecutionException expected) {
1678                assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1679            }
1680            try {
1681                server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1682                fail();
1683            } catch (ExecutionException expected) {
1684                assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1685            }
1686        }
1687
1688        // negative test case for SSL_set_session_creation_enabled(false) on server
1689        {
1690            Hooks cHooks = new Hooks();
1691            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1692                @Override
1693                public long beforeHandshake(long c) throws SSLException {
1694                    long s = super.beforeHandshake(c);
1695                    NativeCrypto.SSL_set_session_creation_enabled(s, false);
1696                    return s;
1697                }
1698            };
1699            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
1700                    null);
1701            @SuppressWarnings("unused")
1702            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
1703                    null);
1704            try {
1705                client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1706                fail();
1707            } catch (ExecutionException expected) {
1708                assertEquals(SSLHandshakeException.class, expected.getCause().getClass());
1709            }
1710            try {
1711                server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1712                fail();
1713            } catch (ExecutionException expected) {
1714                assertEquals(SSLProtocolException.class, expected.getCause().getClass());
1715            }
1716        }
1717    }
1718
1719    public void test_SSL_set_tlsext_host_name() throws Exception {
1720        // NULL SSL
1721        try {
1722            NativeCrypto.SSL_set_tlsext_host_name(NULL, null);
1723            fail();
1724        } catch (NullPointerException expected) {
1725        }
1726
1727        final String hostname = "www.android.com";
1728
1729        {
1730            long c = NativeCrypto.SSL_CTX_new();
1731            long s = NativeCrypto.SSL_new(c);
1732
1733            // null hostname
1734            try {
1735                NativeCrypto.SSL_set_tlsext_host_name(s, null);
1736                fail();
1737            } catch (NullPointerException expected) {
1738            }
1739
1740            // too long hostname
1741            try {
1742                char[] longHostname = new char[256];
1743                Arrays.fill(longHostname, 'w');
1744                NativeCrypto.SSL_set_tlsext_host_name(s, new String(longHostname));
1745                fail();
1746            } catch (SSLException expected) {
1747            }
1748
1749            assertNull(NativeCrypto.SSL_get_servername(s));
1750            NativeCrypto.SSL_set_tlsext_host_name(s, new String(hostname));
1751            assertEquals(hostname, NativeCrypto.SSL_get_servername(s));
1752
1753            NativeCrypto.SSL_free(s);
1754            NativeCrypto.SSL_CTX_free(c);
1755        }
1756
1757        final ServerSocket listener = new ServerSocket(0);
1758
1759        // normal
1760        Hooks cHooks = new Hooks() {
1761            @Override
1762            public long beforeHandshake(long c) throws SSLException {
1763                long s = super.beforeHandshake(c);
1764                NativeCrypto.SSL_set_tlsext_host_name(s, hostname);
1765                return s;
1766            }
1767        };
1768        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1769            @Override
1770            public void afterHandshake(long session, long s, long c,
1771                                       Socket sock, FileDescriptor fd,
1772                                       SSLHandshakeCallbacks callback)
1773                    throws Exception {
1774                assertEquals(hostname, NativeCrypto.SSL_get_servername(s));
1775                super.afterHandshake(session, s, c, sock, fd, callback);
1776            }
1777        };
1778        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1779        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1780        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1781        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1782    }
1783
1784    public void test_SSL_NpnNegotiateSuccess() throws Exception {
1785        final byte[] clientNpnProtocols = new byte[] {
1786                8, 'h', 't', 't', 'p', '/', '1', '.', '1',
1787                3, 'f', 'o', 'o',
1788                6, 's', 'p', 'd', 'y', '/', '2',
1789        };
1790        final byte[] serverNpnProtocols = new byte[] {
1791                6, 's', 'p', 'd', 'y', '/', '2',
1792                3, 'f', 'o', 'o',
1793                3, 'b', 'a', 'r',
1794        };
1795
1796        Hooks cHooks = new Hooks() {
1797            @Override public long beforeHandshake(long context) throws SSLException {
1798                NativeCrypto.SSL_CTX_enable_npn(context);
1799                return super.beforeHandshake(context);
1800            }
1801            @Override public void afterHandshake(long session, long ssl, long context, Socket socket,
1802                    FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
1803                byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl);
1804                assertEquals("spdy/2", new String(negotiated));
1805                assertTrue("NPN should enable cutthrough on the client",
1806                        0 != (NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH));
1807                NativeCrypto.SSL_write(ssl, fd, callback, new byte[] { 42 }, 0, 1,
1808                        (int) ((TIMEOUT_SECONDS * 1000) / 2));
1809                super.afterHandshake(session, ssl, context, socket, fd, callback);
1810            }
1811        };
1812        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1813            @Override public long beforeHandshake(long context) throws SSLException {
1814                NativeCrypto.SSL_CTX_enable_npn(context);
1815                return super.beforeHandshake(context);
1816            }
1817            @Override public void afterHandshake(long session, long ssl, long c, Socket sock,
1818                    FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
1819                byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl);
1820                assertEquals("spdy/2", new String(negotiated));
1821                assertEquals("NPN should not enable cutthrough on the server",
1822                        0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
1823                byte[] buffer = new byte[1];
1824                NativeCrypto.SSL_read(ssl, fd, callback, buffer, 0, 1, 0);
1825                assertEquals(42, buffer[0]);
1826                super.afterHandshake(session, ssl, c, sock, fd, callback);
1827            }
1828        };
1829
1830        ServerSocket listener = new ServerSocket(0);
1831        Future<TestSSLHandshakeCallbacks> client
1832                = handshake(listener, 0, true, cHooks, clientNpnProtocols, null);
1833        Future<TestSSLHandshakeCallbacks> server
1834                = handshake(listener, 0, false, sHooks, serverNpnProtocols, null);
1835        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1836        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1837    }
1838
1839    public void test_SSL_AlpnNegotiateSuccess() throws Exception {
1840        final byte[] clientAlpnProtocols = new byte[] {
1841                8, 'h', 't', 't', 'p', '/', '1', '.', '1',
1842                3, 'f', 'o', 'o',
1843                6, 's', 'p', 'd', 'y', '/', '2',
1844        };
1845        final byte[] serverAlpnProtocols = new byte[] {
1846                6, 's', 'p', 'd', 'y', '/', '2',
1847                3, 'f', 'o', 'o',
1848                3, 'b', 'a', 'r',
1849        };
1850
1851        Hooks cHooks = new Hooks() {
1852            @Override public long beforeHandshake(long context) throws SSLException {
1853                long sslContext = super.beforeHandshake(context);
1854                NativeCrypto.SSL_set_alpn_protos(sslContext, clientAlpnProtocols);
1855                return sslContext;
1856            }
1857            @Override public void afterHandshake(long session, long ssl, long context, Socket socket,
1858                    FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
1859                byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl);
1860                assertEquals("spdy/2", new String(negotiated));
1861                /*
1862                 * There is no callback on the client, so we can't enable
1863                 * cut-through
1864                 */
1865                assertEquals("ALPN should not enable cutthrough on the client", 0,
1866                        NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
1867                super.afterHandshake(session, ssl, context, socket, fd, callback);
1868            }
1869        };
1870        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1871            @Override public void afterHandshake(long session, long ssl, long c, Socket sock,
1872                    FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
1873                byte[] negotiated = NativeCrypto.SSL_get0_alpn_selected(ssl);
1874                assertEquals("spdy/2", new String(negotiated));
1875                assertEquals("ALPN should not enable cutthrough on the server",
1876                        0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
1877                super.afterHandshake(session, ssl, c, sock, fd, callback);
1878            }
1879        };
1880
1881        ServerSocket listener = new ServerSocket(0);
1882        Future<TestSSLHandshakeCallbacks> client
1883                = handshake(listener, 0, true, cHooks, null, null);
1884        Future<TestSSLHandshakeCallbacks> server
1885                = handshake(listener, 0, false, sHooks, null, serverAlpnProtocols);
1886        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1887        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1888    }
1889
1890    public void test_SSL_get_servername_null() throws Exception {
1891        // NULL SSL
1892        try {
1893            NativeCrypto.SSL_get_servername(NULL);
1894            fail();
1895        } catch (NullPointerException expected) {
1896        }
1897
1898        long c = NativeCrypto.SSL_CTX_new();
1899        long s = NativeCrypto.SSL_new(c);
1900        assertNull(NativeCrypto.SSL_get_servername(s));
1901        NativeCrypto.SSL_free(s);
1902        NativeCrypto.SSL_CTX_free(c);
1903
1904        // additional positive testing by test_SSL_set_tlsext_host_name
1905    }
1906
1907    public void test_SSL_renegotiate() throws Exception {
1908        try {
1909            NativeCrypto.SSL_renegotiate(NULL);
1910            fail();
1911        } catch (NullPointerException expected) {
1912        }
1913
1914        final ServerSocket listener = new ServerSocket(0);
1915        Hooks cHooks = new Hooks() {
1916            @Override
1917            public void afterHandshake(long session, long s, long c,
1918                                       Socket sock, FileDescriptor fd,
1919                                       SSLHandshakeCallbacks callback)
1920                    throws Exception {
1921                byte[] buffer = new byte[1];
1922                NativeCrypto.SSL_read(s, fd, callback, buffer, 0, 1, 0);
1923                assertEquals(42, buffer[0]);
1924                super.afterHandshake(session, s, c, sock, fd, callback);
1925            }
1926        };
1927        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1928            @Override
1929            public void afterHandshake(long session, long s, long c,
1930                                       Socket sock, FileDescriptor fd,
1931                                       SSLHandshakeCallbacks callback)
1932                throws Exception {
1933                NativeCrypto.SSL_renegotiate(s);
1934                NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, 0);
1935                super.afterHandshake(session, s, c, sock, fd, callback);
1936            }
1937        };
1938        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1939        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1940        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1941        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1942    }
1943
1944    public void test_SSL_get_certificate() throws Exception {
1945        try {
1946            NativeCrypto.SSL_get_certificate(NULL);
1947            fail();
1948        } catch (NullPointerException expected) {
1949        }
1950
1951        final ServerSocket listener = new ServerSocket(0);
1952        Hooks cHooks = new Hooks() {
1953            @Override
1954            public void afterHandshake(long session, long s, long c,
1955                                       Socket sock, FileDescriptor fd,
1956                                       SSLHandshakeCallbacks callback)
1957                throws Exception {
1958                assertNull(NativeCrypto.SSL_get_certificate(s));
1959                super.afterHandshake(session, s, c, sock, fd, callback);
1960            }
1961        };
1962        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
1963            @Override
1964            public void afterHandshake(long session, long s, long c,
1965                                       Socket sock, FileDescriptor fd,
1966                                       SSLHandshakeCallbacks callback)
1967                    throws Exception {
1968                assertEqualCertificateChains(
1969                                             getServerCertificates(),
1970                                             NativeCrypto.SSL_get_certificate(s));
1971                super.afterHandshake(session, s, c, sock, fd, callback);
1972            }
1973        };
1974        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
1975        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
1976        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1977        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
1978    }
1979
1980    public void test_SSL_get_peer_cert_chain() throws Exception {
1981        try {
1982            NativeCrypto.SSL_get_peer_cert_chain(NULL);
1983            fail();
1984        } catch (NullPointerException expected) {
1985        }
1986
1987        final ServerSocket listener = new ServerSocket(0);
1988
1989        Hooks cHooks = new Hooks() {
1990            @Override
1991            public void afterHandshake(long session, long s, long c,
1992                                       Socket sock, FileDescriptor fd,
1993                                       SSLHandshakeCallbacks callback)
1994                    throws Exception {
1995                long[] cc = NativeCrypto.SSL_get_peer_cert_chain(s);
1996                assertEqualCertificateChains(getServerCertificates(), cc);
1997                for (long ref : cc) {
1998                    NativeCrypto.X509_free(ref);
1999                }
2000                super.afterHandshake(session, s, c, sock, fd, callback);
2001            }
2002        };
2003        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2004        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2005        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2006        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2007        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2008    }
2009
2010    final byte[] BYTES = new byte[] { 2, -3, 5, 127, 0, -128 };
2011
2012    public void test_SSL_read() throws Exception {
2013
2014        // NULL ssl
2015        try {
2016            NativeCrypto.SSL_read(NULL, null, null, null, 0, 0, 0);
2017            fail();
2018        } catch (NullPointerException expected) {
2019        }
2020
2021        // null FileDescriptor
2022        {
2023            long c = NativeCrypto.SSL_CTX_new();
2024            long s = NativeCrypto.SSL_new(c);
2025            try {
2026                NativeCrypto.SSL_read(s, null, DUMMY_CB, null, 0, 0, 0);
2027                fail();
2028            } catch (NullPointerException expected) {
2029            }
2030            NativeCrypto.SSL_free(s);
2031            NativeCrypto.SSL_CTX_free(c);
2032        }
2033
2034        // null SSLHandshakeCallbacks
2035        {
2036            long c = NativeCrypto.SSL_CTX_new();
2037            long s = NativeCrypto.SSL_new(c);
2038            try {
2039                NativeCrypto.SSL_read(s, INVALID_FD, null, null, 0, 0, 0);
2040                fail();
2041            } catch (NullPointerException expected) {
2042            }
2043            NativeCrypto.SSL_free(s);
2044            NativeCrypto.SSL_CTX_free(c);
2045        }
2046
2047        // null byte array
2048        {
2049            long c = NativeCrypto.SSL_CTX_new();
2050            long s = NativeCrypto.SSL_new(c);
2051            try {
2052                NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, null, 0, 0, 0);
2053                fail();
2054            } catch (NullPointerException expected) {
2055            }
2056            NativeCrypto.SSL_free(s);
2057            NativeCrypto.SSL_CTX_free(c);
2058        }
2059
2060        // handshaking not yet performed
2061        {
2062            long c = NativeCrypto.SSL_CTX_new();
2063            long s = NativeCrypto.SSL_new(c);
2064            try {
2065                NativeCrypto.SSL_read(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
2066                fail();
2067            } catch (SSLException expected) {
2068            }
2069            NativeCrypto.SSL_free(s);
2070            NativeCrypto.SSL_CTX_free(c);
2071        }
2072
2073        final ServerSocket listener = new ServerSocket(0);
2074
2075        // normal case
2076        {
2077            Hooks cHooks = new Hooks() {
2078                @Override
2079                public void afterHandshake(long session, long s, long c,
2080                                           Socket sock, FileDescriptor fd,
2081                                           SSLHandshakeCallbacks callback)
2082                        throws Exception {
2083                    byte[] in = new byte[256];
2084                    assertEquals(BYTES.length,
2085                                 NativeCrypto.SSL_read(s,
2086                                                       fd,
2087                                                       callback,
2088                                                       in,
2089                                                       0,
2090                                                       BYTES.length,
2091                                                       0));
2092                    for (int i = 0; i < BYTES.length; i++) {
2093                        assertEquals(BYTES[i], in[i]);
2094                    }
2095                    super.afterHandshake(session, s, c, sock, fd, callback);
2096                }
2097            };
2098            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
2099                @Override
2100                public void afterHandshake(long session, long s, long c,
2101                                           Socket sock, FileDescriptor fd,
2102                                           SSLHandshakeCallbacks callback)
2103                        throws Exception {
2104                    NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length, 0);
2105                    super.afterHandshake(session, s, c, sock, fd, callback);
2106                }
2107            };
2108            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
2109                    null);
2110            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
2111                    null);
2112            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2113            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2114        }
2115
2116        // timeout case
2117        try {
2118            Hooks cHooks = new Hooks() {
2119                @Override
2120                public void afterHandshake(long session, long s, long c,
2121                                           Socket sock, FileDescriptor fd,
2122                                           SSLHandshakeCallbacks callback)
2123                        throws Exception {
2124                    NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 1);
2125                    fail();
2126                }
2127            };
2128            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
2129                @Override
2130                public void afterHandshake(long session, long s, long c,
2131                                           Socket sock, FileDescriptor fd,
2132                                           SSLHandshakeCallbacks callback)
2133                        throws Exception {
2134                    NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0);
2135                    super.afterHandshake(session, s, c, sock, fd, callback);
2136                }
2137            };
2138            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
2139                    null);
2140            @SuppressWarnings("unused")
2141            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
2142                    null);
2143            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2144            fail();
2145        } catch (ExecutionException expected) {
2146            assertEquals(SocketTimeoutException.class, expected.getCause().getClass());
2147        }
2148    }
2149
2150    public void test_SSL_write() throws Exception {
2151        try {
2152            NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0);
2153            fail();
2154        } catch (NullPointerException expected) {
2155        }
2156
2157        // null FileDescriptor
2158        {
2159            long c = NativeCrypto.SSL_CTX_new();
2160            long s = NativeCrypto.SSL_new(c);
2161            try {
2162                NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0);
2163                fail();
2164            } catch (NullPointerException expected) {
2165            }
2166            NativeCrypto.SSL_free(s);
2167            NativeCrypto.SSL_CTX_free(c);
2168        }
2169
2170        // null SSLHandshakeCallbacks
2171        {
2172            long c = NativeCrypto.SSL_CTX_new();
2173            long s = NativeCrypto.SSL_new(c);
2174            try {
2175                NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0);
2176                fail();
2177            } catch (NullPointerException expected) {
2178            }
2179            NativeCrypto.SSL_free(s);
2180            NativeCrypto.SSL_CTX_free(c);
2181        }
2182
2183        // null byte array
2184        {
2185            long c = NativeCrypto.SSL_CTX_new();
2186            long s = NativeCrypto.SSL_new(c);
2187            try {
2188                NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
2189                fail();
2190            } catch (NullPointerException expected) {
2191            }
2192            NativeCrypto.SSL_free(s);
2193            NativeCrypto.SSL_CTX_free(c);
2194        }
2195
2196        // handshaking not yet performed
2197        {
2198            long c = NativeCrypto.SSL_CTX_new();
2199            long s = NativeCrypto.SSL_new(c);
2200            try {
2201                NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
2202                fail();
2203            } catch (SSLException expected) {
2204            }
2205            NativeCrypto.SSL_free(s);
2206            NativeCrypto.SSL_CTX_free(c);
2207        }
2208
2209        // positively tested by test_SSL_read
2210    }
2211
2212    public void test_SSL_interrupt() throws Exception {
2213        // SSL_interrupt is a rare case that tolerates a null SSL argument
2214        NativeCrypto.SSL_interrupt(NULL);
2215
2216        // also works without handshaking
2217        {
2218            long c = NativeCrypto.SSL_CTX_new();
2219            long s = NativeCrypto.SSL_new(c);
2220            NativeCrypto.SSL_interrupt(s);
2221            NativeCrypto.SSL_free(s);
2222            NativeCrypto.SSL_CTX_free(c);
2223        }
2224
2225        final ServerSocket listener = new ServerSocket(0);
2226
2227        Hooks cHooks = new Hooks() {
2228            @Override
2229            public void afterHandshake(long session, long s, long c,
2230                                       Socket sock, FileDescriptor fd,
2231                                       SSLHandshakeCallbacks callback)
2232                    throws Exception {
2233                NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0);
2234                super.afterHandshake(session, s, c, sock, fd, callback);
2235            }
2236        };
2237        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
2238            @Override
2239            public void afterHandshake(long session, final long s, long c,
2240                                       Socket sock, FileDescriptor fd,
2241                                       SSLHandshakeCallbacks callback)
2242                    throws Exception {
2243                new Thread() {
2244                    @Override
2245                    public void run() {
2246                        try {
2247                            Thread.sleep(1*1000);
2248                            NativeCrypto.SSL_interrupt(s);
2249                        } catch (Exception e) {
2250                        }
2251                    }
2252                }.start();
2253                assertEquals(-1, NativeCrypto.SSL_read(s, fd, callback, new byte[1], 0, 1, 0));
2254                super.afterHandshake(session, s, c, sock, fd, callback);
2255            }
2256        };
2257        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2258        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2259        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2260        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2261    }
2262
2263    private static abstract class SSLSessionWrappedTask {
2264        public abstract void run(long sslSession) throws Exception;
2265    }
2266
2267    private void wrapWithSSLSession(SSLSessionWrappedTask task) throws Exception {
2268        long c = NativeCrypto.SSL_CTX_new();
2269        long s = NativeCrypto.SSL_new(c);
2270        try {
2271            task.run(s);
2272        } finally {
2273            NativeCrypto.SSL_free(s);
2274            NativeCrypto.SSL_CTX_free(c);
2275        }
2276    }
2277
2278    public void test_SSL_shutdown() throws Exception {
2279
2280        // null FileDescriptor
2281        wrapWithSSLSession(new SSLSessionWrappedTask() {
2282            @Override
2283            public void run(long sslSession) throws Exception {
2284                try {
2285                    NativeCrypto.SSL_shutdown(sslSession, null, DUMMY_CB);
2286                    fail();
2287                } catch (NullPointerException expected) {
2288                }
2289            }
2290        });
2291
2292        // null SSLHandshakeCallbacks
2293        wrapWithSSLSession(new SSLSessionWrappedTask() {
2294            @Override
2295            public void run(long sslSession) throws Exception {
2296                try {
2297                    NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, null);
2298                    fail();
2299                } catch (NullPointerException expected) {
2300                }
2301            }
2302        });
2303
2304        // SSL_shutdown is a rare case that tolerates a null SSL argument
2305        NativeCrypto.SSL_shutdown(NULL, INVALID_FD, DUMMY_CB);
2306
2307        // handshaking not yet performed
2308        wrapWithSSLSession(new SSLSessionWrappedTask() {
2309            @Override
2310            public void run(long sslSession) throws Exception {
2311                try {
2312                    NativeCrypto.SSL_shutdown(sslSession, INVALID_FD, DUMMY_CB);
2313                    fail();
2314                } catch (SocketException expected) {
2315                }
2316            }
2317        });
2318
2319        // positively tested elsewhere because handshake uses use
2320        // SSL_shutdown to ensure SSL_SESSIONs are reused.
2321    }
2322
2323    public void test_SSL_free() throws Exception {
2324        try {
2325            NativeCrypto.SSL_free(NULL);
2326            fail();
2327        } catch (NullPointerException expected) {
2328        }
2329
2330        long c = NativeCrypto.SSL_CTX_new();
2331        NativeCrypto.SSL_free(NativeCrypto.SSL_new(c));
2332        NativeCrypto.SSL_CTX_free(c);
2333
2334        // additional positive testing elsewhere because handshake
2335        // uses use SSL_free to cleanup in afterHandshake.
2336    }
2337
2338    public void test_SSL_SESSION_session_id() throws Exception {
2339        try {
2340            NativeCrypto.SSL_SESSION_session_id(NULL);
2341            fail();
2342        } catch (NullPointerException expected) {
2343        }
2344
2345        final ServerSocket listener = new ServerSocket(0);
2346
2347        Hooks cHooks = new Hooks() {
2348            @Override
2349            public void afterHandshake(long session, long s, long c,
2350                                       Socket sock, FileDescriptor fd,
2351                                       SSLHandshakeCallbacks callback)
2352                    throws Exception {
2353                byte[] id = NativeCrypto.SSL_SESSION_session_id(session);
2354                assertNotNull(id);
2355                assertEquals(32, id.length);
2356                super.afterHandshake(session, s, c, sock, fd, callback);
2357            }
2358        };
2359        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2360        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2361        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2362        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2363        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2364    }
2365
2366    public void test_SSL_SESSION_get_time() throws Exception {
2367        try {
2368            NativeCrypto.SSL_SESSION_get_time(NULL);
2369            fail();
2370        } catch (NullPointerException expected) {
2371        }
2372
2373        final ServerSocket listener = new ServerSocket(0);
2374
2375        {
2376            Hooks cHooks = new Hooks() {
2377                @Override
2378                public void afterHandshake(long session, long s, long c,
2379                                           Socket sock, FileDescriptor fd,
2380                                           SSLHandshakeCallbacks callback)
2381                        throws Exception {
2382                    long time = NativeCrypto.SSL_SESSION_get_time(session);
2383                    assertTrue(time != 0);
2384                    assertTrue(time < System.currentTimeMillis());
2385                    super.afterHandshake(session, s, c, sock, fd, callback);
2386                }
2387            };
2388            Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2389            Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null,
2390                    null);
2391            Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null,
2392                    null);
2393            client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2394            server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2395        }
2396    }
2397
2398    public void test_SSL_SESSION_get_version() throws Exception {
2399        try {
2400            NativeCrypto.SSL_SESSION_get_version(NULL);
2401            fail();
2402        } catch (NullPointerException expected) {
2403        }
2404
2405        final ServerSocket listener = new ServerSocket(0);
2406
2407        Hooks cHooks = new Hooks() {
2408            @Override
2409            public void afterHandshake(long session, long s, long c,
2410                                       Socket sock, FileDescriptor fd,
2411                                       SSLHandshakeCallbacks callback)
2412                    throws Exception {
2413                String v = NativeCrypto.SSL_SESSION_get_version(session);
2414                assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(v));
2415                super.afterHandshake(session, s, c, sock, fd, callback);
2416            }
2417        };
2418        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2419        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2420        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2421        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2422        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2423    }
2424
2425    public void test_SSL_SESSION_cipher() throws Exception {
2426        try {
2427            NativeCrypto.SSL_SESSION_cipher(NULL);
2428            fail();
2429        } catch (NullPointerException expected) {
2430        }
2431
2432        final ServerSocket listener = new ServerSocket(0);
2433
2434        Hooks cHooks = new Hooks() {
2435            @Override
2436            public void afterHandshake(long session, long s, long c,
2437                                       Socket sock, FileDescriptor fd,
2438                                       SSLHandshakeCallbacks callback)
2439                        throws Exception {
2440                String a = NativeCrypto.SSL_SESSION_cipher(session);
2441                assertTrue(NativeCrypto.OPENSSL_TO_STANDARD_CIPHER_SUITES.containsKey(a));
2442                super.afterHandshake(session, s, c, sock, fd, callback);
2443            }
2444        };
2445        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2446        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2447        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2448        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2449        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2450    }
2451
2452    public void test_SSL_SESSION_free() throws Exception {
2453        try {
2454            NativeCrypto.SSL_SESSION_free(NULL);
2455            fail();
2456        } catch (NullPointerException expected) {
2457        }
2458
2459        // additional positive testing elsewhere because handshake
2460        // uses use SSL_SESSION_free to cleanup in afterHandshake.
2461    }
2462
2463    public void test_i2d_SSL_SESSION() throws Exception {
2464        try {
2465            NativeCrypto.i2d_SSL_SESSION(NULL);
2466            fail();
2467        } catch (NullPointerException expected) {
2468        }
2469
2470        final ServerSocket listener = new ServerSocket(0);
2471
2472        Hooks cHooks = new Hooks() {
2473            @Override
2474            public void afterHandshake(long session, long s, long c,
2475                                       Socket sock, FileDescriptor fd,
2476                                       SSLHandshakeCallbacks callback)
2477                    throws Exception {
2478                byte[] b = NativeCrypto.i2d_SSL_SESSION(session);
2479                assertNotNull(b);
2480                long session2 = NativeCrypto.d2i_SSL_SESSION(b);
2481                assertTrue(session2 != NULL);
2482
2483                // Make sure d2i_SSL_SESSION retores SSL_SESSION_cipher value http://b/7091840
2484                assertTrue(NativeCrypto.SSL_SESSION_cipher(session2) != null);
2485                assertEquals(NativeCrypto.SSL_SESSION_cipher(session),
2486                             NativeCrypto.SSL_SESSION_cipher(session2));
2487
2488                NativeCrypto.SSL_SESSION_free(session2);
2489                super.afterHandshake(session, s, c, sock, fd, callback);
2490            }
2491        };
2492        Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
2493        Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null, null);
2494        Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null, null);
2495        client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2496        server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
2497    }
2498
2499    public void test_d2i_SSL_SESSION() throws Exception {
2500        try {
2501            NativeCrypto.d2i_SSL_SESSION(null);
2502            fail();
2503        } catch (NullPointerException expected) {
2504        }
2505
2506        assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[0]));
2507        assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[1]));
2508
2509        // positive testing by test_i2d_SSL_SESSION
2510    }
2511
2512    public void test_X509_NAME_hashes() {
2513        // ensure these hash functions are stable over time since the
2514        // /system/etc/security/cacerts CA filenames have to be
2515        // consistent with the output.
2516        X500Principal name = new X500Principal("CN=localhost");
2517        assertEquals(-1372642656, NativeCrypto.X509_NAME_hash(name)); // SHA1
2518        assertEquals(-1626170662, NativeCrypto.X509_NAME_hash_old(name)); // MD5
2519    }
2520
2521    public void test_RAND_bytes_Success() throws Exception {
2522        byte[] output = new byte[128];
2523        NativeCrypto.RAND_bytes(output);
2524
2525        boolean isZero = true;
2526        for (int i = 0; i < output.length; i++) {
2527            isZero &= (output[i] == 0);
2528        }
2529
2530        assertFalse("Random output was zero. This is a very low probability event (1 in 2^128) "
2531                + "and probably indicates an error.", isZero);
2532    }
2533
2534    public void test_RAND_bytes_Null_Failure() throws Exception {
2535        byte[] output = null;
2536        try {
2537            NativeCrypto.RAND_bytes(output);
2538            fail("Should be an error on null buffer input");
2539        } catch (RuntimeException expected) {
2540        }
2541    }
2542
2543    public void test_EVP_get_digestbyname() throws Exception {
2544        assertTrue(NativeCrypto.EVP_get_digestbyname("sha256") != NULL);
2545
2546        try {
2547            NativeCrypto.EVP_get_digestbyname(null);
2548            fail();
2549        } catch (NullPointerException expected) {
2550        }
2551
2552        try {
2553            NativeCrypto.EVP_get_digestbyname("");
2554            NativeCrypto.EVP_get_digestbyname("foobar");
2555            fail();
2556        } catch (RuntimeException expected) {
2557        }
2558    }
2559
2560    public void test_EVP_SignInit() throws Exception {
2561        final NativeRef.EVP_MD_CTX ctx = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
2562        assertEquals(1,
2563                NativeCrypto.EVP_SignInit(ctx, NativeCrypto.EVP_get_digestbyname("sha256")));
2564
2565        try {
2566            NativeCrypto.EVP_SignInit(ctx, 0);
2567            fail();
2568        } catch (RuntimeException expected) {
2569        }
2570    }
2571
2572    public void test_get_RSA_private_params() throws Exception {
2573        try {
2574            NativeCrypto.get_RSA_private_params(null);
2575        } catch (NullPointerException expected) {
2576        }
2577
2578        try {
2579            NativeCrypto.get_RSA_private_params(null);
2580        } catch (NullPointerException expected) {
2581        }
2582
2583        // Test getting params for the wrong kind of key.
2584        final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
2585        assertFalse(groupCtx == NULL);
2586        NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
2587        NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
2588        try {
2589            NativeCrypto.get_RSA_private_params(ctx);
2590            fail();
2591        } catch (RuntimeException expected) {
2592        }
2593    }
2594
2595    public void test_get_RSA_public_params() throws Exception {
2596        try {
2597            NativeCrypto.get_RSA_public_params(null);
2598        } catch (NullPointerException expected) {
2599        }
2600
2601        try {
2602            NativeCrypto.get_RSA_public_params(null);
2603        } catch (NullPointerException expected) {
2604        }
2605
2606        // Test getting params for the wrong kind of key.
2607        final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
2608        assertFalse(groupCtx == NULL);
2609        NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupCtx);
2610        NativeRef.EVP_PKEY ctx = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
2611        try {
2612            NativeCrypto.get_RSA_public_params(ctx);
2613            fail();
2614        } catch (RuntimeException expected) {
2615        }
2616    }
2617
2618    public void test_RSA_size_null_key_Failure() throws Exception {
2619        try {
2620            NativeCrypto.RSA_size(null);
2621            fail("Expecting null pointer exception for RSA_size with null key");
2622        } catch (NullPointerException expected) {}
2623    }
2624
2625    public void test_RSA_private_encrypt_null_key_Failure() throws Exception {
2626        try {
2627            NativeCrypto.RSA_private_encrypt(0, new byte[0], new byte[0],
2628                    null, 0);
2629            fail("Expecting null pointer exception for RSA_private encrypt with null key");
2630        } catch (NullPointerException expected) {}
2631    }
2632
2633    public void test_RSA_private_decrypt_null_key_Failure() throws Exception {
2634        try {
2635            NativeCrypto.RSA_private_decrypt(0, new byte[0], new byte[0],
2636 null, 0);
2637            fail("Expecting null pointer exception for RSA_private_decrypt with null key");
2638        } catch (NullPointerException expected) {}
2639    }
2640
2641    public void test_RSA_public_encrypt_null_key_Failure() throws Exception {
2642        try {
2643            NativeCrypto.RSA_public_encrypt(0, new byte[0], new byte[0], null,
2644                    0);
2645            fail("Expecting null pointer exception for RSA_public encrypt with null key");
2646        } catch (NullPointerException expected) {}
2647    }
2648
2649    public void test_RSA_public_decrypt_null_key_Failure() throws Exception {
2650        try {
2651            NativeCrypto.RSA_public_decrypt(0, new byte[0], new byte[0], null,
2652                    0);
2653            fail("Expecting null pointer exception for RSA_public decrypt with null key");
2654        } catch (NullPointerException expected) {}
2655    }
2656
2657    /*
2658     * Test vector generation:
2659     * openssl rand -hex 16
2660     */
2661    private static final byte[] AES_128_KEY = new byte[] {
2662            (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2,
2663            (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29,
2664            (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f,
2665    };
2666
2667    public void testEC_GROUP() throws Exception {
2668        /* Test using NIST's P-256 curve */
2669        check_EC_GROUP(NativeCrypto.EC_CURVE_GFP, "prime256v1",
2670                "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
2671                "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
2672                "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
2673                "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
2674                "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
2675                "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
2676                1L);
2677    }
2678
2679    private void check_EC_GROUP(int type, String name, String pStr, String aStr, String bStr,
2680            String xStr, String yStr, String nStr, long hLong) throws Exception {
2681        long groupRef = NativeCrypto.EC_GROUP_new_by_curve_name(name);
2682        assertFalse(groupRef == NULL);
2683        NativeRef.EC_GROUP group = new NativeRef.EC_GROUP(groupRef);
2684        assertEquals(NativeCrypto.OBJ_txt2nid_longName(name),
2685                NativeCrypto.EC_GROUP_get_curve_name(group));
2686        assertEquals(type, NativeCrypto.get_EC_GROUP_type(group));
2687
2688        // prime
2689        BigInteger p = new BigInteger(pStr, 16);
2690        // first coefficient
2691        BigInteger a = new BigInteger(aStr, 16);
2692        // second coefficient
2693        BigInteger b = new BigInteger(bStr, 16);
2694        // x affine coordinate of generator
2695        BigInteger x = new BigInteger(xStr, 16);
2696        // y affine coordinate of generator
2697        BigInteger y = new BigInteger(yStr, 16);
2698        // order of the generator
2699        BigInteger n = new BigInteger(nStr, 16);
2700        // cofactor of generator
2701        BigInteger h = BigInteger.valueOf(hLong);
2702
2703        byte[][] pab = NativeCrypto.EC_GROUP_get_curve(group);
2704        assertEquals(3, pab.length);
2705
2706        BigInteger p2 = new BigInteger(pab[0]);
2707        assertEquals(p, p2);
2708
2709        BigInteger a2 = new BigInteger(pab[1]);
2710        assertEquals(a, a2);
2711
2712        BigInteger b2 = new BigInteger(pab[2]);
2713        assertEquals(b, b2);
2714
2715        NativeRef.EC_POINT point = new NativeRef.EC_POINT(
2716                NativeCrypto.EC_GROUP_get_generator(group));
2717
2718        byte[][] xy = NativeCrypto.EC_POINT_get_affine_coordinates(group, point);
2719        assertEquals(2, xy.length);
2720
2721        BigInteger x2 = new BigInteger(xy[0]);
2722        assertEquals(x, x2);
2723
2724        BigInteger y2 = new BigInteger(xy[1]);
2725        assertEquals(y, y2);
2726
2727        BigInteger n2 = new BigInteger(NativeCrypto.EC_GROUP_get_order(group));
2728        assertEquals(n, n2);
2729
2730        BigInteger h2 = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(group));
2731        assertEquals(h, h2);
2732
2733        NativeRef.EVP_PKEY key1 = new NativeRef.EVP_PKEY(NativeCrypto.EC_KEY_generate_key(group));
2734        NativeRef.EC_GROUP groupTmp = new NativeRef.EC_GROUP(NativeCrypto.EC_KEY_get1_group(key1));
2735        assertEquals(NativeCrypto.EC_GROUP_get_curve_name(group),
2736                NativeCrypto.EC_GROUP_get_curve_name(groupTmp));
2737    }
2738
2739    public void test_EC_KEY_get_private_key_null_key_Failure() throws Exception {
2740        try {
2741            NativeCrypto.EC_KEY_get_private_key(null);
2742            fail();
2743        } catch (NullPointerException expected) {}
2744    }
2745
2746    public void test_EC_KEY_get_public_key_null_key_Failure() throws Exception {
2747        try {
2748            NativeCrypto.EC_KEY_get_public_key(null);
2749            fail();
2750        } catch (NullPointerException expected) {}
2751    }
2752
2753    public void test_ECKeyPairGenerator_CurvesAreValid() throws Exception {
2754        OpenSSLECKeyPairGenerator.assertCurvesAreValid();
2755    }
2756
2757    public void test_ECDH_compute_key_null_key_Failure() throws Exception {
2758        final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
2759        assertFalse(groupCtx == NULL);
2760        NativeRef.EC_GROUP groupRef = new NativeRef.EC_GROUP(groupCtx);
2761        NativeRef.EVP_PKEY pkey1Ref = new NativeRef.EVP_PKEY(
2762                NativeCrypto.EC_KEY_generate_key(groupRef));
2763        NativeRef.EVP_PKEY pkey2Ref = new NativeRef.EVP_PKEY(
2764                NativeCrypto.EC_KEY_generate_key(groupRef));
2765
2766        byte[] out = new byte[128];
2767        int outOffset = 0;
2768        // Assert that the method under test works fine with the two
2769        // non-null keys
2770        NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, pkey2Ref);
2771
2772        // Assert that it fails when only the first key is null
2773        try {
2774            NativeCrypto.ECDH_compute_key(out, outOffset, null, pkey2Ref);
2775            fail();
2776        } catch (NullPointerException expected) {
2777        }
2778
2779        // Assert that it fails when only the second key is null
2780        try {
2781            NativeCrypto.ECDH_compute_key(out, outOffset, pkey1Ref, null);
2782            fail();
2783        } catch (NullPointerException expected) {
2784        }
2785    }
2786
2787    public void test_EVP_CipherInit_ex_Null_Failure() throws Exception {
2788        final NativeRef.EVP_CIPHER_CTX ctx = new NativeRef.EVP_CIPHER_CTX(
2789                NativeCrypto.EVP_CIPHER_CTX_new());
2790        final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
2791
2792        try {
2793            NativeCrypto.EVP_CipherInit_ex(null, evpCipher, null, null, true);
2794            fail("Null context should throw NullPointerException");
2795        } catch (NullPointerException expected) {
2796        }
2797
2798        /* Initialize encrypting. */
2799        NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, true);
2800        NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, true);
2801
2802        /* Initialize decrypting. */
2803        NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, null, null, false);
2804        NativeCrypto.EVP_CipherInit_ex(ctx, NULL, null, null, false);
2805    }
2806
2807    public void test_EVP_CipherInit_ex_Success() throws Exception {
2808        final NativeRef.EVP_CIPHER_CTX ctx = new NativeRef.EVP_CIPHER_CTX(
2809                NativeCrypto.EVP_CIPHER_CTX_new());
2810        final long evpCipher = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
2811        NativeCrypto.EVP_CipherInit_ex(ctx, evpCipher, AES_128_KEY, null, true);
2812    }
2813
2814    public void test_EVP_CIPHER_iv_length() throws Exception {
2815        long aes128ecb = NativeCrypto.EVP_get_cipherbyname("aes-128-ecb");
2816        assertEquals(0, NativeCrypto.EVP_CIPHER_iv_length(aes128ecb));
2817
2818        long aes128cbc = NativeCrypto.EVP_get_cipherbyname("aes-128-cbc");
2819        assertEquals(16, NativeCrypto.EVP_CIPHER_iv_length(aes128cbc));
2820    }
2821
2822    public void test_OpenSSLKey_toJava() throws Exception {
2823        OpenSSLKey key1;
2824
2825        BigInteger e = BigInteger.valueOf(65537);
2826        key1 = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(1024, e.toByteArray()));
2827        assertTrue(key1.getPublicKey() instanceof RSAPublicKey);
2828
2829        final long groupCtx = NativeCrypto.EC_GROUP_new_by_curve_name("prime256v1");
2830        assertFalse(groupCtx == NULL);
2831        NativeRef.EC_GROUP group1 = new NativeRef.EC_GROUP(groupCtx);
2832        key1 = new OpenSSLKey(NativeCrypto.EC_KEY_generate_key(group1));
2833        assertTrue(key1.getPublicKey() instanceof ECPublicKey);
2834    }
2835
2836    public void test_create_BIO_InputStream() throws Exception {
2837        byte[] actual = "Test".getBytes();
2838        ByteArrayInputStream is = new ByteArrayInputStream(actual);
2839
2840        @SuppressWarnings("resource")
2841        OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
2842        try {
2843            byte[] buffer = new byte[1024];
2844            int numRead = NativeCrypto.BIO_read(bis.getBioContext(), buffer);
2845            assertEquals(actual.length, numRead);
2846            assertEquals(Arrays.toString(actual),
2847                    Arrays.toString(Arrays.copyOfRange(buffer, 0, numRead)));
2848        } finally {
2849            bis.release();
2850        }
2851    }
2852
2853    public void test_create_BIO_OutputStream() throws Exception {
2854        byte[] actual = "Test".getBytes();
2855        ByteArrayOutputStream os = new ByteArrayOutputStream();
2856
2857        long ctx = NativeCrypto.create_BIO_OutputStream(os);
2858        try {
2859            NativeCrypto.BIO_write(ctx, actual, 0, actual.length);
2860            assertEquals(actual.length, os.size());
2861            assertEquals(Arrays.toString(actual), Arrays.toString(os.toByteArray()));
2862        } finally {
2863            NativeCrypto.BIO_free_all(ctx);
2864        }
2865    }
2866
2867    private static void assertContains(String actualValue, String expectedSubstring) {
2868        if (actualValue == null) {
2869            return;
2870        }
2871        if (actualValue.contains(expectedSubstring)) {
2872            return;
2873        }
2874        fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\"");
2875    }
2876}
2877