org_conscrypt_NativeCrypto.cpp revision 2d089e18deae231149737cad6ce00f1e137a7199
1/*
2 * Copyright (C) 2007-2008 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
17/**
18 * Native glue for Java class org.conscrypt.NativeCrypto
19 */
20
21#define TO_STRING1(x) #x
22#define TO_STRING(x) TO_STRING1(x)
23#ifndef JNI_JARJAR_PREFIX
24#define CONSCRYPT_UNBUNDLED
25#define JNI_JARJAR_PREFIX
26#endif
27
28#define LOG_TAG "NativeCrypto"
29
30#include <arpa/inet.h>
31#include <fcntl.h>
32#include <sys/socket.h>
33#include <unistd.h>
34
35#include <jni.h>
36
37#include <openssl/asn1t.h>
38#include <openssl/dsa.h>
39#include <openssl/engine.h>
40#include <openssl/err.h>
41#include <openssl/evp.h>
42#include <openssl/rand.h>
43#include <openssl/rsa.h>
44#include <openssl/ssl.h>
45#include <openssl/x509v3.h>
46
47#include "AsynchronousSocketCloseMonitor.h"
48#include "cutils/log.h"
49#include "JNIHelp.h"
50#include "JniConstants.h"
51#include "JniException.h"
52#include "NetFd.h"
53#include "ScopedLocalRef.h"
54#include "ScopedPrimitiveArray.h"
55#include "ScopedUtfChars.h"
56#include "UniquePtr.h"
57
58#undef WITH_JNI_TRACE
59#undef WITH_JNI_TRACE_DATA
60
61/*
62 * How to use this for debugging with Wireshark:
63 *
64 * 1. Pull lines from logcat to a file that looks like (without quotes):
65 *     "RSA Session-ID:... Master-Key:..." <CR>
66 *     "RSA Session-ID:... Master-Key:..." <CR>
67 *     <etc>
68 * 2. Start Wireshark
69 * 3. Go to Edit -> Preferences -> SSL -> (Pre-)Master-Key log and fill in
70 *    the file you put the lines in above.
71 * 4. Follow the stream that corresponds to the desired "Session-ID" in
72 *    the Server Hello.
73 */
74#undef WITH_JNI_TRACE_KEYS
75
76#ifdef WITH_JNI_TRACE
77#define JNI_TRACE(...) \
78        ((void)ALOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__));     \
79/*
80        ((void)printf("I/" LOG_TAG "-jni:"));         \
81        ((void)printf(__VA_ARGS__));          \
82        ((void)printf("\n"))
83*/
84#else
85#define JNI_TRACE(...) ((void)0)
86#endif
87// don't overwhelm logcat
88#define WITH_JNI_TRACE_DATA_CHUNK_SIZE 512
89
90static JavaVM* gJavaVM;
91static jclass openSslOutputStreamClass;
92
93static jclass byteArrayClass;
94static jclass calendarClass;
95static jclass objectClass;
96static jclass objectArrayClass;
97static jclass integerClass;
98static jclass inputStreamClass;
99static jclass outputStreamClass;
100static jclass stringClass;
101
102static jmethodID calendar_setMethod;
103static jmethodID inputStream_readMethod;
104static jmethodID integer_valueOfMethod;
105static jmethodID openSslInputStream_readLineMethod;
106static jmethodID outputStream_writeMethod;
107static jmethodID outputStream_flushMethod;
108
109struct OPENSSL_Delete {
110    void operator()(void* p) const {
111        OPENSSL_free(p);
112    }
113};
114typedef UniquePtr<unsigned char, OPENSSL_Delete> Unique_OPENSSL_str;
115
116struct BIO_Delete {
117    void operator()(BIO* p) const {
118        BIO_free(p);
119    }
120};
121typedef UniquePtr<BIO, BIO_Delete> Unique_BIO;
122
123struct BIGNUM_Delete {
124    void operator()(BIGNUM* p) const {
125        BN_free(p);
126    }
127};
128typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
129
130struct ASN1_INTEGER_Delete {
131    void operator()(ASN1_INTEGER* p) const {
132        ASN1_INTEGER_free(p);
133    }
134};
135typedef UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> Unique_ASN1_INTEGER;
136
137struct DH_Delete {
138    void operator()(DH* p) const {
139        DH_free(p);
140    }
141};
142typedef UniquePtr<DH, DH_Delete> Unique_DH;
143
144struct DSA_Delete {
145    void operator()(DSA* p) const {
146        DSA_free(p);
147    }
148};
149typedef UniquePtr<DSA, DSA_Delete> Unique_DSA;
150
151struct EC_GROUP_Delete {
152    void operator()(EC_GROUP* p) const {
153        EC_GROUP_clear_free(p);
154    }
155};
156typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP;
157
158struct EC_POINT_Delete {
159    void operator()(EC_POINT* p) const {
160        EC_POINT_clear_free(p);
161    }
162};
163typedef UniquePtr<EC_POINT, EC_POINT_Delete> Unique_EC_POINT;
164
165struct EC_KEY_Delete {
166    void operator()(EC_KEY* p) const {
167        EC_KEY_free(p);
168    }
169};
170typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
171
172struct EVP_MD_CTX_Delete {
173    void operator()(EVP_MD_CTX* p) const {
174        EVP_MD_CTX_destroy(p);
175    }
176};
177typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX;
178
179struct EVP_CIPHER_CTX_Delete {
180    void operator()(EVP_CIPHER_CTX* p) const {
181        EVP_CIPHER_CTX_free(p);
182    }
183};
184typedef UniquePtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_Delete> Unique_EVP_CIPHER_CTX;
185
186struct EVP_PKEY_Delete {
187    void operator()(EVP_PKEY* p) const {
188        EVP_PKEY_free(p);
189    }
190};
191typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
192
193struct PKCS8_PRIV_KEY_INFO_Delete {
194    void operator()(PKCS8_PRIV_KEY_INFO* p) const {
195        PKCS8_PRIV_KEY_INFO_free(p);
196    }
197};
198typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
199
200struct RSA_Delete {
201    void operator()(RSA* p) const {
202        RSA_free(p);
203    }
204};
205typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
206
207struct ASN1_BIT_STRING_Delete {
208    void operator()(ASN1_BIT_STRING* p) const {
209        ASN1_BIT_STRING_free(p);
210    }
211};
212typedef UniquePtr<ASN1_BIT_STRING, ASN1_BIT_STRING_Delete> Unique_ASN1_BIT_STRING;
213
214struct ASN1_OBJECT_Delete {
215    void operator()(ASN1_OBJECT* p) const {
216        ASN1_OBJECT_free(p);
217    }
218};
219typedef UniquePtr<ASN1_OBJECT, ASN1_OBJECT_Delete> Unique_ASN1_OBJECT;
220
221struct ASN1_GENERALIZEDTIME_Delete {
222    void operator()(ASN1_GENERALIZEDTIME* p) const {
223        ASN1_GENERALIZEDTIME_free(p);
224    }
225};
226typedef UniquePtr<ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME_Delete> Unique_ASN1_GENERALIZEDTIME;
227
228struct SSL_Delete {
229    void operator()(SSL* p) const {
230        SSL_free(p);
231    }
232};
233typedef UniquePtr<SSL, SSL_Delete> Unique_SSL;
234
235struct SSL_CTX_Delete {
236    void operator()(SSL_CTX* p) const {
237        SSL_CTX_free(p);
238    }
239};
240typedef UniquePtr<SSL_CTX, SSL_CTX_Delete> Unique_SSL_CTX;
241
242struct X509_Delete {
243    void operator()(X509* p) const {
244        X509_free(p);
245    }
246};
247typedef UniquePtr<X509, X509_Delete> Unique_X509;
248
249struct X509_NAME_Delete {
250    void operator()(X509_NAME* p) const {
251        X509_NAME_free(p);
252    }
253};
254typedef UniquePtr<X509_NAME, X509_NAME_Delete> Unique_X509_NAME;
255
256struct PKCS7_Delete {
257    void operator()(PKCS7* p) const {
258        PKCS7_free(p);
259    }
260};
261typedef UniquePtr<PKCS7, PKCS7_Delete> Unique_PKCS7;
262
263struct sk_SSL_CIPHER_Delete {
264    void operator()(STACK_OF(SSL_CIPHER)* p) const {
265        // We don't own SSL_CIPHER references, so no need for pop_free
266        sk_SSL_CIPHER_free(p);
267    }
268};
269typedef UniquePtr<STACK_OF(SSL_CIPHER), sk_SSL_CIPHER_Delete> Unique_sk_SSL_CIPHER;
270
271struct sk_X509_Delete {
272    void operator()(STACK_OF(X509)* p) const {
273        sk_X509_pop_free(p, X509_free);
274    }
275};
276typedef UniquePtr<STACK_OF(X509), sk_X509_Delete> Unique_sk_X509;
277
278struct sk_X509_NAME_Delete {
279    void operator()(STACK_OF(X509_NAME)* p) const {
280        sk_X509_NAME_pop_free(p, X509_NAME_free);
281    }
282};
283typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME;
284
285struct sk_ASN1_OBJECT_Delete {
286    void operator()(STACK_OF(ASN1_OBJECT)* p) const {
287        sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free);
288    }
289};
290typedef UniquePtr<STACK_OF(ASN1_OBJECT), sk_ASN1_OBJECT_Delete> Unique_sk_ASN1_OBJECT;
291
292struct sk_GENERAL_NAME_Delete {
293    void operator()(STACK_OF(GENERAL_NAME)* p) const {
294        sk_GENERAL_NAME_pop_free(p, GENERAL_NAME_free);
295    }
296};
297typedef UniquePtr<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_Delete> Unique_sk_GENERAL_NAME;
298
299/**
300 * Many OpenSSL APIs take ownership of an argument on success but don't free the argument
301 * on failure. This means we need to tell our scoped pointers when we've transferred ownership,
302 * without triggering a warning by not using the result of release().
303 */
304#define OWNERSHIP_TRANSFERRED(obj) \
305    do { typeof (obj.release()) _dummy __attribute__((unused)) = obj.release(); } while(0)
306
307/**
308 * Frees the SSL error state.
309 *
310 * OpenSSL keeps an "error stack" per thread, and given that this code
311 * can be called from arbitrary threads that we don't keep track of,
312 * we err on the side of freeing the error state promptly (instead of,
313 * say, at thread death).
314 */
315static void freeOpenSslErrorState(void) {
316    ERR_clear_error();
317    ERR_remove_state(0);
318}
319
320/**
321 * Throws a OutOfMemoryError with the given string as a message.
322 */
323static void jniThrowOutOfMemory(JNIEnv* env, const char* message) {
324    jniThrowException(env, "java/lang/OutOfMemoryError", message);
325}
326
327/**
328 * Throws a BadPaddingException with the given string as a message.
329 */
330static void throwBadPaddingException(JNIEnv* env, const char* message) {
331    JNI_TRACE("throwBadPaddingException %s", message);
332    jniThrowException(env, "javax/crypto/BadPaddingException", message);
333}
334
335/**
336 * Throws a SignatureException with the given string as a message.
337 */
338static void throwSignatureException(JNIEnv* env, const char* message) {
339    JNI_TRACE("throwSignatureException %s", message);
340    jniThrowException(env, "java/security/SignatureException", message);
341}
342
343/**
344 * Throws a InvalidKeyException with the given string as a message.
345 */
346static void throwInvalidKeyException(JNIEnv* env, const char* message) {
347    JNI_TRACE("throwInvalidKeyException %s", message);
348    jniThrowException(env, "java/security/InvalidKeyException", message);
349}
350
351/**
352 * Throws a SignatureException with the given string as a message.
353 */
354static void throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
355    JNI_TRACE("throwIllegalBlockSizeException %s", message);
356    jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message);
357}
358
359/**
360 * Throws a NoSuchAlgorithmException with the given string as a message.
361 */
362static void throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
363    JNI_TRACE("throwUnknownAlgorithmException %s", message);
364    jniThrowException(env, "java/security/NoSuchAlgorithmException", message);
365}
366
367static void throwForAsn1Error(JNIEnv* env, int reason, const char *message) {
368    switch (reason) {
369    case ASN1_R_UNABLE_TO_DECODE_RSA_KEY:
370    case ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY:
371    case ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE:
372    case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE:
373    case ASN1_R_WRONG_PUBLIC_KEY_TYPE:
374        throwInvalidKeyException(env, message);
375        break;
376    case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
377        throwNoSuchAlgorithmException(env, message);
378        break;
379    default:
380        jniThrowRuntimeException(env, message);
381        break;
382    }
383}
384
385static void throwForEvpError(JNIEnv* env, int reason, const char *message) {
386    switch (reason) {
387    case EVP_R_BAD_DECRYPT:
388        throwBadPaddingException(env, message);
389        break;
390    case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
391    case EVP_R_WRONG_FINAL_BLOCK_LENGTH:
392        throwIllegalBlockSizeException(env, message);
393        break;
394    case EVP_R_BAD_KEY_LENGTH:
395    case EVP_R_BN_DECODE_ERROR:
396    case EVP_R_BN_PUBKEY_ERROR:
397    case EVP_R_INVALID_KEY_LENGTH:
398    case EVP_R_MISSING_PARAMETERS:
399    case EVP_R_UNSUPPORTED_KEY_SIZE:
400    case EVP_R_UNSUPPORTED_KEYLENGTH:
401        throwInvalidKeyException(env, message);
402        break;
403    case EVP_R_WRONG_PUBLIC_KEY_TYPE:
404        throwSignatureException(env, message);
405        break;
406    case EVP_R_UNSUPPORTED_ALGORITHM:
407        throwNoSuchAlgorithmException(env, message);
408        break;
409    default:
410        jniThrowRuntimeException(env, message);
411        break;
412    }
413}
414
415static void throwForRsaError(JNIEnv* env, int reason, const char *message) {
416    switch (reason) {
417    case RSA_R_BLOCK_TYPE_IS_NOT_01:
418    case RSA_R_BLOCK_TYPE_IS_NOT_02:
419        throwBadPaddingException(env, message);
420        break;
421    case RSA_R_ALGORITHM_MISMATCH:
422    case RSA_R_BAD_SIGNATURE:
423    case RSA_R_DATA_GREATER_THAN_MOD_LEN:
424    case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
425    case RSA_R_INVALID_MESSAGE_LENGTH:
426    case RSA_R_WRONG_SIGNATURE_LENGTH:
427        throwSignatureException(env, message);
428        break;
429    case RSA_R_UNKNOWN_ALGORITHM_TYPE:
430        throwNoSuchAlgorithmException(env, message);
431        break;
432    case RSA_R_MODULUS_TOO_LARGE:
433    case RSA_R_NO_PUBLIC_EXPONENT:
434        throwInvalidKeyException(env, message);
435        break;
436    default:
437        jniThrowRuntimeException(env, message);
438        break;
439    }
440}
441
442static void throwForX509Error(JNIEnv* env, int reason, const char *message) {
443    switch (reason) {
444    case X509_R_UNSUPPORTED_ALGORITHM:
445        throwNoSuchAlgorithmException(env, message);
446        break;
447    default:
448        jniThrowRuntimeException(env, message);
449        break;
450    }
451}
452
453/*
454 * Checks this thread's OpenSSL error queue and throws a RuntimeException if
455 * necessary.
456 *
457 * @return true if an exception was thrown, false if not.
458 */
459static bool throwExceptionIfNecessary(JNIEnv* env, const char* location  __attribute__ ((unused))) {
460    const char* file;
461    int line;
462    const char* data;
463    int flags;
464    unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
465    int result = false;
466
467    if (error != 0) {
468        char message[256];
469        ERR_error_string_n(error, message, sizeof(message));
470        int library = ERR_GET_LIB(error);
471        int reason = ERR_GET_REASON(error);
472        JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s",
473                  location, error, library, reason, file, line, message,
474                  (flags & ERR_TXT_STRING) ? data : "(no data)");
475        switch (library) {
476        case ERR_LIB_RSA:
477            throwForRsaError(env, reason, message);
478            break;
479        case ERR_LIB_ASN1:
480            throwForAsn1Error(env, reason, message);
481            break;
482        case ERR_LIB_EVP:
483            throwForEvpError(env, reason, message);
484            break;
485        case ERR_LIB_X509:
486            throwForX509Error(env, reason, message);
487            break;
488        case ERR_LIB_DSA:
489            throwInvalidKeyException(env, message);
490            break;
491        default:
492            jniThrowRuntimeException(env, message);
493            break;
494        }
495        result = true;
496    }
497
498    freeOpenSslErrorState();
499    return result;
500}
501
502/**
503 * Throws an SocketTimeoutException with the given string as a message.
504 */
505static void throwSocketTimeoutException(JNIEnv* env, const char* message) {
506    JNI_TRACE("throwSocketTimeoutException %s", message);
507    jniThrowException(env, "java/net/SocketTimeoutException", message);
508}
509
510/**
511 * Throws a javax.net.ssl.SSLException with the given string as a message.
512 */
513static void throwSSLExceptionStr(JNIEnv* env, const char* message) {
514    JNI_TRACE("throwSSLExceptionStr %s", message);
515    jniThrowException(env, "javax/net/ssl/SSLException", message);
516}
517
518/**
519 * Throws a javax.net.ssl.SSLProcotolException with the given string as a message.
520 */
521static void throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
522    JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
523    jniThrowException(env, "javax/net/ssl/SSLProtocolException", message);
524}
525
526/**
527 * Throws an SSLException with a message constructed from the current
528 * SSL errors. This will also log the errors.
529 *
530 * @param env the JNI environment
531 * @param ssl the possibly NULL SSL
532 * @param sslErrorCode error code returned from SSL_get_error() or
533 * SSL_ERROR_NONE to probe with ERR_get_error
534 * @param message null-ok; general error message
535 */
536static void throwSSLExceptionWithSslErrors(
537        JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message) {
538
539    if (message == NULL) {
540        message = "SSL error";
541    }
542
543    // First consult the SSL error code for the general message.
544    const char* sslErrorStr = NULL;
545    switch (sslErrorCode) {
546        case SSL_ERROR_NONE:
547            if (ERR_peek_error() == 0) {
548                sslErrorStr = "OK";
549            } else {
550                sslErrorStr = "";
551            }
552            break;
553        case SSL_ERROR_SSL:
554            sslErrorStr = "Failure in SSL library, usually a protocol error";
555            break;
556        case SSL_ERROR_WANT_READ:
557            sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
558            break;
559        case SSL_ERROR_WANT_WRITE:
560            sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
561            break;
562        case SSL_ERROR_WANT_X509_LOOKUP:
563            sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
564            break;
565        case SSL_ERROR_SYSCALL:
566            sslErrorStr = "I/O error during system call";
567            break;
568        case SSL_ERROR_ZERO_RETURN:
569            sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
570            break;
571        case SSL_ERROR_WANT_CONNECT:
572            sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
573            break;
574        case SSL_ERROR_WANT_ACCEPT:
575            sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
576            break;
577        default:
578            sslErrorStr = "Unknown SSL error";
579    }
580
581    // Prepend either our explicit message or a default one.
582    char* str;
583    if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
584        // problem with asprintf, just throw argument message, log everything
585        throwSSLExceptionStr(env, message);
586        ALOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
587        freeOpenSslErrorState();
588        return;
589    }
590
591    char* allocStr = str;
592
593    // For protocol errors, SSL might have more information.
594    if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
595        // Append each error as an additional line to the message.
596        for (;;) {
597            char errStr[256];
598            const char* file;
599            int line;
600            const char* data;
601            int flags;
602            unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
603            if (err == 0) {
604                break;
605            }
606
607            ERR_error_string_n(err, errStr, sizeof(errStr));
608
609            int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
610                               (allocStr == NULL) ? "" : allocStr,
611                               errStr,
612                               file,
613                               line,
614                               (flags & ERR_TXT_STRING) ? data : "(no data)",
615                               flags);
616
617            if (ret < 0) {
618                break;
619            }
620
621            free(allocStr);
622            allocStr = str;
623        }
624    // For errors during system calls, errno might be our friend.
625    } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
626        if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
627            free(allocStr);
628            allocStr = str;
629        }
630    // If the error code is invalid, print it.
631    } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
632        if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
633            free(allocStr);
634            allocStr = str;
635        }
636    }
637
638    if (sslErrorCode == SSL_ERROR_SSL) {
639        throwSSLProtocolExceptionStr(env, allocStr);
640    } else {
641        throwSSLExceptionStr(env, allocStr);
642    }
643
644    ALOGV("%s", allocStr);
645    free(allocStr);
646    freeOpenSslErrorState();
647}
648
649/**
650 * Helper function that grabs the casts an ssl pointer and then checks for nullness.
651 * If this function returns NULL and <code>throwIfNull</code> is
652 * passed as <code>true</code>, then this function will call
653 * <code>throwSSLExceptionStr</code> before returning, so in this case of
654 * NULL, a caller of this function should simply return and allow JNI
655 * to do its thing.
656 *
657 * @param env the JNI environment
658 * @param ssl_address; the ssl_address pointer as an integer
659 * @param throwIfNull whether to throw if the SSL pointer is NULL
660 * @returns the pointer, which may be NULL
661 */
662static SSL_CTX* to_SSL_CTX(JNIEnv* env, jlong ssl_ctx_address, bool throwIfNull) {
663    SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
664    if ((ssl_ctx == NULL) && throwIfNull) {
665        JNI_TRACE("ssl_ctx == null");
666        jniThrowNullPointerException(env, "ssl_ctx == null");
667    }
668    return ssl_ctx;
669}
670
671static SSL* to_SSL(JNIEnv* env, jlong ssl_address, bool throwIfNull) {
672    SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address));
673    if ((ssl == NULL) && throwIfNull) {
674        JNI_TRACE("ssl == null");
675        jniThrowNullPointerException(env, "ssl == null");
676    }
677    return ssl;
678}
679
680static SSL_SESSION* to_SSL_SESSION(JNIEnv* env, jlong ssl_session_address, bool throwIfNull) {
681    SSL_SESSION* ssl_session
682        = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
683    if ((ssl_session == NULL) && throwIfNull) {
684        JNI_TRACE("ssl_session == null");
685        jniThrowNullPointerException(env, "ssl_session == null");
686    }
687    return ssl_session;
688}
689
690static SSL_CIPHER* to_SSL_CIPHER(JNIEnv* env, jlong ssl_cipher_address, bool throwIfNull) {
691    SSL_CIPHER* ssl_cipher
692        = reinterpret_cast<SSL_CIPHER*>(static_cast<uintptr_t>(ssl_cipher_address));
693    if ((ssl_cipher == NULL) && throwIfNull) {
694        JNI_TRACE("ssl_cipher == null");
695        jniThrowNullPointerException(env, "ssl_cipher == null");
696    }
697    return ssl_cipher;
698}
699
700/**
701 * Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the
702 * fly. Returns true on success. If the return value is false, there is a
703 * pending exception.
704 */
705static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) {
706    JNI_TRACE("arrayToBignum(%p, %p)", source, *dest);
707
708    ScopedByteArrayRO sourceBytes(env, source);
709    if (sourceBytes.get() == NULL) {
710        JNI_TRACE("arrayToBignum(%p) => NULL", source);
711        return false;
712    }
713    *dest = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()),
714                           sourceBytes.size(),
715                           NULL);
716    if (*dest == NULL) {
717        jniThrowRuntimeException(env, "Conversion to BIGNUM failed");
718        JNI_TRACE("arrayToBignum(%p) => threw exception", source);
719        return false;
720    }
721
722    JNI_TRACE("arrayToBignum(%p) => %p", source, *dest);
723    return true;
724}
725
726/**
727 * Converts an OpenSSL BIGNUM to a Java byte[] array.
728 */
729static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source, const char* sourceName) {
730    JNI_TRACE("bignumToArray(%p, %s)", source, sourceName);
731
732    if (source == NULL) {
733        jniThrowNullPointerException(env, sourceName);
734        return NULL;
735    }
736
737    jbyteArray javaBytes = env->NewByteArray(BN_num_bytes(source) + 1);
738    ScopedByteArrayRW bytes(env, javaBytes);
739    if (bytes.get() == NULL) {
740        JNI_TRACE("bignumToArray(%p, %s) => NULL", source, sourceName);
741        return NULL;
742    }
743
744    unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
745
746    // Set the sign for the Java code.
747    if (BN_is_negative(source)) {
748        *tmp = 0xFF;
749    } else {
750        *tmp = 0x00;
751    }
752
753    if (BN_num_bytes(source) > 0 && BN_bn2bin(source, tmp + 1) <= 0) {
754        throwExceptionIfNecessary(env, "bignumToArray");
755        return NULL;
756    }
757
758    JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes);
759    return javaBytes;
760}
761
762/**
763 * Converts various OpenSSL ASN.1 types to a jbyteArray with DER-encoded data
764 * inside. The "i2d_func" function pointer is a function of the "i2d_<TYPE>"
765 * from the OpenSSL ASN.1 API.
766 */
767template<typename T, int (*i2d_func)(T*, unsigned char**)>
768jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj) {
769    if (obj == NULL) {
770        jniThrowNullPointerException(env, "ASN1 input == null");
771        JNI_TRACE("ASN1ToByteArray(%p) => null input", obj);
772        return NULL;
773    }
774
775    int derLen = i2d_func(obj, NULL);
776    if (derLen < 0) {
777        throwExceptionIfNecessary(env, "ASN1ToByteArray");
778        JNI_TRACE("ASN1ToByteArray(%p) => measurement failed", obj);
779        return NULL;
780    }
781
782    ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(derLen));
783    if (byteArray.get() == NULL) {
784        JNI_TRACE("ASN1ToByteArray(%p) => creating byte array failed", obj);
785        return NULL;
786    }
787
788    ScopedByteArrayRW bytes(env, byteArray.get());
789    if (bytes.get() == NULL) {
790        JNI_TRACE("ASN1ToByteArray(%p) => using byte array failed", obj);
791        return NULL;
792    }
793
794    unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
795    int ret = i2d_func(obj, &p);
796    if (ret < 0) {
797        throwExceptionIfNecessary(env, "ASN1ToByteArray");
798        JNI_TRACE("ASN1ToByteArray(%p) => final conversion failed", obj);
799        return NULL;
800    }
801
802    JNI_TRACE("ASN1ToByteArray(%p) => success (%d bytes written)", obj, ret);
803    return byteArray.release();
804}
805
806template<typename T, T* (*d2i_func)(T**, const unsigned char**, long)>
807T* ByteArrayToASN1(JNIEnv* env, jbyteArray byteArray) {
808    ScopedByteArrayRO bytes(env, byteArray);
809    if (bytes.get() == NULL) {
810        JNI_TRACE("ByteArrayToASN1(%p) => using byte array failed", byteArray);
811        return 0;
812    }
813
814    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
815    return d2i_func(NULL, &tmp, bytes.size());
816}
817
818/**
819 * Converts ASN.1 BIT STRING to a jbooleanArray.
820 */
821jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) {
822    int size = bitStr->length * 8;
823    if (bitStr->flags & ASN1_STRING_FLAG_BITS_LEFT) {
824        size -= bitStr->flags & 0x07;
825    }
826
827    ScopedLocalRef<jbooleanArray> bitsRef(env, env->NewBooleanArray(size));
828    if (bitsRef.get() == NULL) {
829        return NULL;
830    }
831
832    ScopedBooleanArrayRW bitsArray(env, bitsRef.get());
833    for (int i = 0; i < static_cast<int>(bitsArray.size()); i++) {
834        bitsArray[i] = ASN1_BIT_STRING_get_bit(bitStr, i);
835    }
836
837    return bitsRef.release();
838}
839
840/**
841 * To avoid the round-trip to ASN.1 and back in X509_dup, we just up the reference count.
842 */
843static X509* X509_dup_nocopy(X509* x509) {
844    if (x509 == NULL) {
845        return NULL;
846    }
847    CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
848    return x509;
849}
850
851/**
852 * BIO for InputStream
853 */
854class BIO_Stream {
855public:
856    BIO_Stream(jobject stream) :
857            mEof(false) {
858        JNIEnv* env = getEnv();
859        mStream = env->NewGlobalRef(stream);
860    }
861
862    ~BIO_Stream() {
863        JNIEnv* env = getEnv();
864
865        env->DeleteGlobalRef(mStream);
866    }
867
868    bool isEof() const {
869        JNI_TRACE("isEof? %s", mEof ? "yes" : "no");
870        return mEof;
871    }
872
873    int flush() {
874        JNIEnv* env = getEnv();
875        if (env == NULL) {
876            return -1;
877        }
878
879        env->CallVoidMethod(mStream, outputStream_flushMethod);
880        if (env->ExceptionCheck()) {
881            return -1;
882        }
883
884        return 1;
885    }
886
887protected:
888    jobject getStream() {
889        return mStream;
890    }
891
892    void setEof(bool eof) {
893        mEof = eof;
894    }
895
896    JNIEnv* getEnv() {
897        JNIEnv* env;
898
899        if (gJavaVM->AttachCurrentThread(&env, NULL) < 0) {
900            return NULL;
901        }
902
903        return env;
904    }
905
906private:
907    jobject mStream;
908    bool mEof;
909};
910
911class BIO_InputStream : public BIO_Stream {
912public:
913    BIO_InputStream(jobject stream) :
914            BIO_Stream(stream) {
915    }
916
917    int read(char *buf, int len) {
918        return read_internal(buf, len, inputStream_readMethod);
919    }
920
921    int gets(char *buf, int len) {
922        if (len > PEM_LINE_LENGTH) {
923            len = PEM_LINE_LENGTH;
924        }
925
926        int read = read_internal(buf, len - 1, openSslInputStream_readLineMethod);
927        buf[read] = '\0';
928        JNI_TRACE("BIO::gets \"%s\"", buf);
929        return read;
930    }
931
932private:
933    int read_internal(char *buf, int len, jmethodID method) {
934        JNIEnv* env = getEnv();
935        if (env == NULL) {
936            JNI_TRACE("BIO_InputStream::read could not get JNIEnv");
937            return -1;
938        }
939
940        ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len));
941        if (javaBytes.get() == NULL) {
942            JNI_TRACE("BIO_InputStream::read failed call to NewByteArray");
943            return -1;
944        }
945
946        jint read = env->CallIntMethod(getStream(), method, javaBytes.get());
947        if (env->ExceptionCheck()) {
948            JNI_TRACE("BIO_InputStream::read failed call to InputStream#read");
949            return -1;
950        }
951
952        /* Java uses -1 to indicate EOF condition. */
953        if (read == -1) {
954            setEof(true);
955            read = 0;
956        } else if (read > 0) {
957            env->GetByteArrayRegion(javaBytes.get(), 0, read, reinterpret_cast<jbyte*>(buf));
958        }
959
960        return read;
961    }
962
963public:
964    /** Length of PEM-encoded line (64) plus CR plus NULL */
965    static const int PEM_LINE_LENGTH = 66;
966};
967
968class BIO_OutputStream : public BIO_Stream {
969public:
970    BIO_OutputStream(jobject stream) :
971            BIO_Stream(stream) {
972    }
973
974    int write(const char *buf, int len) {
975        JNIEnv* env = getEnv();
976        if (env == NULL) {
977            JNI_TRACE("BIO_OutputStream::write => could not get JNIEnv");
978            return -1;
979        }
980
981        ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len));
982        if (javaBytes.get() == NULL) {
983            JNI_TRACE("BIO_OutputStream::write => failed call to NewByteArray");
984            return -1;
985        }
986
987        env->SetByteArrayRegion(javaBytes.get(), 0, len, reinterpret_cast<const jbyte*>(buf));
988
989        env->CallVoidMethod(getStream(), outputStream_writeMethod, javaBytes.get());
990        if (env->ExceptionCheck()) {
991            JNI_TRACE("BIO_OutputStream::write => failed call to OutputStream#write");
992            return -1;
993        }
994
995        return len;
996    }
997};
998
999static int bio_stream_create(BIO *b) {
1000    b->init = 1;
1001    b->num = 0;
1002    b->ptr = NULL;
1003    b->flags = 0;
1004    return 1;
1005}
1006
1007static int bio_stream_destroy(BIO *b) {
1008    if (b == NULL) {
1009        return 0;
1010    }
1011
1012    if (b->ptr != NULL) {
1013        delete static_cast<BIO_Stream*>(b->ptr);
1014        b->ptr = NULL;
1015    }
1016
1017    b->init = 0;
1018    b->flags = 0;
1019    return 1;
1020}
1021
1022static int bio_stream_read(BIO *b, char *buf, int len) {
1023    BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr);
1024    return stream->read(buf, len);
1025}
1026
1027static int bio_stream_write(BIO *b, const char *buf, int len) {
1028    BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr);
1029    return stream->write(buf, len);
1030}
1031
1032static int bio_stream_puts(BIO *b, const char *buf) {
1033    BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr);
1034    return stream->write(buf, strlen(buf));
1035}
1036
1037static int bio_stream_gets(BIO *b, char *buf, int len) {
1038    BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr);
1039    return stream->gets(buf, len);
1040}
1041
1042static void bio_stream_assign(BIO *b, BIO_Stream* stream) {
1043    b->ptr = static_cast<void*>(stream);
1044}
1045
1046static long bio_stream_ctrl(BIO *b, int cmd, long, void *) {
1047    BIO_Stream* stream = static_cast<BIO_Stream*>(b->ptr);
1048
1049    switch (cmd) {
1050    case BIO_CTRL_EOF:
1051        return stream->isEof() ? 1 : 0;
1052    case BIO_CTRL_FLUSH:
1053        return stream->flush();
1054    default:
1055        return 0;
1056    }
1057}
1058
1059static BIO_METHOD stream_bio_method = {
1060        ( 100 | 0x0400 ), /* source/sink BIO */
1061        "InputStream/OutputStream BIO",
1062        bio_stream_write, /* bio_write */
1063        bio_stream_read, /* bio_read */
1064        bio_stream_puts, /* bio_puts */
1065        bio_stream_gets, /* bio_gets */
1066        bio_stream_ctrl, /* bio_ctrl */
1067        bio_stream_create, /* bio_create */
1068        bio_stream_destroy, /* bio_free */
1069        NULL, /* no bio_callback_ctrl */
1070};
1071
1072/**
1073 * Copied from libnativehelper NetworkUtilites.cpp
1074 */
1075static bool setBlocking(int fd, bool blocking) {
1076    int flags = fcntl(fd, F_GETFL);
1077    if (flags == -1) {
1078        return false;
1079    }
1080
1081    if (!blocking) {
1082        flags |= O_NONBLOCK;
1083    } else {
1084        flags &= ~O_NONBLOCK;
1085    }
1086
1087    int rc = fcntl(fd, F_SETFL, flags);
1088    return (rc != -1);
1089}
1090
1091/**
1092 * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I
1093 * suppose there are not many other ways to do this on a Linux system (modulo
1094 * isomorphism).
1095 */
1096#define MUTEX_TYPE pthread_mutex_t
1097#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
1098#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
1099#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
1100#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
1101#define THREAD_ID pthread_self()
1102#define THROW_SSLEXCEPTION (-2)
1103#define THROW_SOCKETTIMEOUTEXCEPTION (-3)
1104#define THROWN_EXCEPTION (-4)
1105
1106static MUTEX_TYPE* mutex_buf = NULL;
1107
1108static void locking_function(int mode, int n, const char*, int) {
1109    if (mode & CRYPTO_LOCK) {
1110        MUTEX_LOCK(mutex_buf[n]);
1111    } else {
1112        MUTEX_UNLOCK(mutex_buf[n]);
1113    }
1114}
1115
1116static unsigned long id_function(void) {
1117    return ((unsigned long)THREAD_ID);
1118}
1119
1120int THREAD_setup(void) {
1121    mutex_buf = new MUTEX_TYPE[CRYPTO_num_locks()];
1122    if (!mutex_buf) {
1123        return 0;
1124    }
1125
1126    for (int i = 0; i < CRYPTO_num_locks(); ++i) {
1127        MUTEX_SETUP(mutex_buf[i]);
1128    }
1129
1130    CRYPTO_set_id_callback(id_function);
1131    CRYPTO_set_locking_callback(locking_function);
1132
1133    return 1;
1134}
1135
1136int THREAD_cleanup(void) {
1137    if (!mutex_buf) {
1138        return 0;
1139    }
1140
1141    CRYPTO_set_id_callback(NULL);
1142    CRYPTO_set_locking_callback(NULL);
1143
1144    for (int i = 0; i < CRYPTO_num_locks( ); i++) {
1145        MUTEX_CLEANUP(mutex_buf[i]);
1146    }
1147
1148    free(mutex_buf);
1149    mutex_buf = NULL;
1150
1151    return 1;
1152}
1153
1154/**
1155 * Initialization phase for every OpenSSL job: Loads the Error strings, the
1156 * crypto algorithms and reset the OpenSSL library
1157 */
1158static void NativeCrypto_clinit(JNIEnv*, jclass)
1159{
1160    SSL_load_error_strings();
1161    ERR_load_crypto_strings();
1162    SSL_library_init();
1163    OpenSSL_add_all_algorithms();
1164    THREAD_setup();
1165}
1166
1167static void NativeCrypto_ENGINE_load_dynamic(JNIEnv*, jclass) {
1168    JNI_TRACE("ENGINE_load_dynamic()");
1169
1170    ENGINE_load_dynamic();
1171}
1172
1173static jlong NativeCrypto_ENGINE_by_id(JNIEnv* env, jclass, jstring idJava) {
1174    JNI_TRACE("ENGINE_by_id(%p)", idJava);
1175
1176    ScopedUtfChars id(env, idJava);
1177    if (id.c_str() == NULL) {
1178        JNI_TRACE("ENGINE_by_id(%p) => id == null", idJava);
1179        return 0;
1180    }
1181    JNI_TRACE("ENGINE_by_id(\"%s\")", id.c_str());
1182
1183    ENGINE* e = ENGINE_by_id(id.c_str());
1184    if (e == NULL) {
1185        freeOpenSslErrorState();
1186    }
1187
1188    JNI_TRACE("ENGINE_by_id(\"%s\") => %p", id.c_str(), e);
1189    return reinterpret_cast<uintptr_t>(e);
1190}
1191
1192static jint NativeCrypto_ENGINE_add(JNIEnv* env, jclass, jlong engineRef) {
1193    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1194    JNI_TRACE("ENGINE_add(%p)", e);
1195
1196    if (e == NULL) {
1197        jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
1198        return 0;
1199    }
1200
1201    int ret = ENGINE_add(e);
1202
1203    /*
1204     * We tolerate errors, because the most likely error is that
1205     * the ENGINE is already in the list.
1206     */
1207    freeOpenSslErrorState();
1208
1209    JNI_TRACE("ENGINE_add(%p) => %d", e, ret);
1210    return ret;
1211}
1212
1213static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jlong engineRef) {
1214    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1215    JNI_TRACE("ENGINE_init(%p)", e);
1216
1217    if (e == NULL) {
1218        jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
1219        return 0;
1220    }
1221
1222    int ret = ENGINE_init(e);
1223    JNI_TRACE("ENGINE_init(%p) => %d", e, ret);
1224    return ret;
1225}
1226
1227static jint NativeCrypto_ENGINE_finish(JNIEnv* env, jclass, jlong engineRef) {
1228    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1229    JNI_TRACE("ENGINE_finish(%p)", e);
1230
1231    if (e == NULL) {
1232        jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
1233        return 0;
1234    }
1235
1236    int ret = ENGINE_finish(e);
1237    JNI_TRACE("ENGINE_finish(%p) => %d", e, ret);
1238    return ret;
1239}
1240
1241static jint NativeCrypto_ENGINE_free(JNIEnv* env, jclass, jlong engineRef) {
1242    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1243    JNI_TRACE("ENGINE_free(%p)", e);
1244
1245    if (e == NULL) {
1246        jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
1247        return 0;
1248    }
1249
1250    int ret = ENGINE_free(e);
1251    JNI_TRACE("ENGINE_free(%p) => %d", e, ret);
1252    return ret;
1253}
1254
1255static jlong NativeCrypto_ENGINE_load_private_key(JNIEnv* env, jclass, jlong engineRef,
1256        jstring idJava) {
1257    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1258    JNI_TRACE("ENGINE_load_private_key(%p, %p)", e, idJava);
1259
1260    ScopedUtfChars id(env, idJava);
1261    if (id.c_str() == NULL) {
1262        jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL");
1263        return 0;
1264    }
1265
1266    Unique_EVP_PKEY pkey(ENGINE_load_private_key(e, id.c_str(), NULL, NULL));
1267    if (pkey.get() == NULL) {
1268        throwExceptionIfNecessary(env, "ENGINE_load_private_key");
1269        return 0;
1270    }
1271
1272    JNI_TRACE("ENGINE_load_private_key(%p, %p) => %p", e, idJava, pkey.get());
1273    return reinterpret_cast<uintptr_t>(pkey.release());
1274}
1275
1276static jstring NativeCrypto_ENGINE_get_id(JNIEnv* env, jclass, jlong engineRef)
1277{
1278    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1279    JNI_TRACE("ENGINE_get_id(%p)", e);
1280
1281    if (e == NULL) {
1282        jniThrowNullPointerException(env, "engine == null");
1283        JNI_TRACE("ENGINE_get_id(%p) => engine == null", e);
1284        return NULL;
1285    }
1286
1287    const char *id = ENGINE_get_id(e);
1288    ScopedLocalRef<jstring> idJava(env, env->NewStringUTF(id));
1289
1290    JNI_TRACE("ENGINE_get_id(%p) => \"%s\"", e, id);
1291    return idJava.release();
1292}
1293
1294static jint NativeCrypto_ENGINE_ctrl_cmd_string(JNIEnv* env, jclass, jlong engineRef,
1295        jstring cmdJava, jstring argJava, jint cmd_optional)
1296{
1297    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
1298    JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d)", e, cmdJava, argJava, cmd_optional);
1299
1300    if (e == NULL) {
1301        jniThrowNullPointerException(env, "engine == null");
1302        JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d) => engine == null", e, cmdJava, argJava,
1303                cmd_optional);
1304        return 0;
1305    }
1306
1307    ScopedUtfChars cmdChars(env, cmdJava);
1308    if (cmdChars.c_str() == NULL) {
1309        return 0;
1310    }
1311
1312    UniquePtr<ScopedUtfChars> arg;
1313    const char* arg_c_str = NULL;
1314    if (argJava != NULL) {
1315        arg.reset(new ScopedUtfChars(env, argJava));
1316        arg_c_str = arg->c_str();
1317        if (arg_c_str == NULL) {
1318            return 0;
1319        }
1320    }
1321    JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d)", e, cmdChars.c_str(), arg_c_str,
1322            cmd_optional);
1323
1324    int ret = ENGINE_ctrl_cmd_string(e, cmdChars.c_str(), arg_c_str, cmd_optional);
1325    if (ret != 1) {
1326        throwExceptionIfNecessary(env, "ENGINE_ctrl_cmd_string");
1327        JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => threw error", e,
1328                cmdChars.c_str(), arg_c_str, cmd_optional);
1329        return 0;
1330    }
1331
1332    JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => %d", e, cmdChars.c_str(),
1333            arg_c_str, cmd_optional, ret);
1334    return ret;
1335}
1336
1337/**
1338 * public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
1339 *                                           byte[] pub_key, byte[] priv_key);
1340 */
1341static jlong NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass,
1342                                               jbyteArray p, jbyteArray q, jbyteArray g,
1343                                               jbyteArray pub_key, jbyteArray priv_key) {
1344    JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p)",
1345              p, q, g, pub_key, priv_key);
1346
1347    Unique_DSA dsa(DSA_new());
1348    if (dsa.get() == NULL) {
1349        jniThrowRuntimeException(env, "DSA_new failed");
1350        return 0;
1351    }
1352
1353    if (!arrayToBignum(env, p, &dsa->p)) {
1354        return 0;
1355    }
1356
1357    if (!arrayToBignum(env, q, &dsa->q)) {
1358        return 0;
1359    }
1360
1361    if (!arrayToBignum(env, g, &dsa->g)) {
1362        return 0;
1363    }
1364
1365    if (pub_key != NULL && !arrayToBignum(env, pub_key, &dsa->pub_key)) {
1366        return 0;
1367    }
1368
1369    if (priv_key != NULL && !arrayToBignum(env, priv_key, &dsa->priv_key)) {
1370        return 0;
1371    }
1372
1373    if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL
1374            || (dsa->pub_key == NULL && dsa->priv_key == NULL)) {
1375        jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
1376        return 0;
1377    }
1378
1379    Unique_EVP_PKEY pkey(EVP_PKEY_new());
1380    if (pkey.get() == NULL) {
1381        jniThrowRuntimeException(env, "EVP_PKEY_new failed");
1382        return 0;
1383    }
1384    if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
1385        jniThrowRuntimeException(env, "EVP_PKEY_assign_DSA failed");
1386        return 0;
1387    }
1388    OWNERSHIP_TRANSFERRED(dsa);
1389    JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p) => %p",
1390              p, q, g, pub_key, priv_key, pkey.get());
1391    return reinterpret_cast<jlong>(pkey.release());
1392}
1393
1394/**
1395 * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
1396 */
1397static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass,
1398                                               jbyteArray n, jbyteArray e, jbyteArray d,
1399                                               jbyteArray p, jbyteArray q,
1400                                               jbyteArray dmp1, jbyteArray dmq1,
1401                                               jbyteArray iqmp) {
1402    JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, iqmp=%p)",
1403            n, e, d, p, q, dmp1, dmq1, iqmp);
1404
1405    Unique_RSA rsa(RSA_new());
1406    if (rsa.get() == NULL) {
1407        jniThrowRuntimeException(env, "RSA_new failed");
1408        return 0;
1409    }
1410
1411    if (e == NULL && d == NULL) {
1412        jniThrowException(env, "java/lang/IllegalArgumentException", "e == NULL && d == NULL");
1413        JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == NULL && d == NULL");
1414        return 0;
1415    }
1416
1417    if (!arrayToBignum(env, n, &rsa->n)) {
1418        return 0;
1419    }
1420
1421    if (e != NULL && !arrayToBignum(env, e, &rsa->e)) {
1422        return 0;
1423    }
1424
1425    if (d != NULL && !arrayToBignum(env, d, &rsa->d)) {
1426        return 0;
1427    }
1428
1429    if (p != NULL && !arrayToBignum(env, p, &rsa->p)) {
1430        return 0;
1431    }
1432
1433    if (q != NULL && !arrayToBignum(env, q, &rsa->q)) {
1434        return 0;
1435    }
1436
1437    if (dmp1 != NULL && !arrayToBignum(env, dmp1, &rsa->dmp1)) {
1438        return 0;
1439    }
1440
1441    if (dmq1 != NULL && !arrayToBignum(env, dmq1, &rsa->dmq1)) {
1442        return 0;
1443    }
1444
1445    if (iqmp != NULL && !arrayToBignum(env, iqmp, &rsa->iqmp)) {
1446        return 0;
1447    }
1448
1449#ifdef WITH_JNI_TRACE
1450    if (p != NULL && q != NULL) {
1451        int check = RSA_check_key(rsa.get());
1452        JNI_TRACE("EVP_PKEY_new_RSA(...) RSA_check_key returns %d", check);
1453    }
1454#endif
1455
1456    if (rsa->n == NULL || (rsa->e == NULL && rsa->d == NULL)) {
1457        jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
1458        return 0;
1459    }
1460
1461    /*
1462     * If the private exponent is available, there is the potential to do signing
1463     * operations. If the public exponent is also available, OpenSSL will do RSA
1464     * blinding. Enable it if possible.
1465     */
1466    if (rsa->d != NULL) {
1467        if (rsa->e != NULL) {
1468            JNI_TRACE("EVP_PKEY_new_RSA(...) enabling RSA blinding => %p", rsa.get());
1469            RSA_blinding_on(rsa.get(), NULL);
1470        } else {
1471            JNI_TRACE("EVP_PKEY_new_RSA(...) disabling RSA blinding => %p", rsa.get());
1472            RSA_blinding_off(rsa.get());
1473        }
1474    }
1475
1476    Unique_EVP_PKEY pkey(EVP_PKEY_new());
1477    if (pkey.get() == NULL) {
1478        jniThrowRuntimeException(env, "EVP_PKEY_new failed");
1479        return 0;
1480    }
1481    if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
1482        jniThrowRuntimeException(env, "EVP_PKEY_new failed");
1483        return 0;
1484    }
1485    OWNERSHIP_TRANSFERRED(rsa);
1486    JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, iqmp=%p) => %p",
1487            n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get());
1488    return reinterpret_cast<uintptr_t>(pkey.release());
1489}
1490
1491static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jlong groupRef,
1492        jlong pubkeyRef, jbyteArray keyJavaBytes) {
1493    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
1494    const EC_POINT* pubkey = reinterpret_cast<const EC_POINT*>(pubkeyRef);
1495    JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", group, pubkey, keyJavaBytes);
1496
1497    Unique_BIGNUM key(NULL);
1498    if (keyJavaBytes != NULL) {
1499        BIGNUM* keyRef;
1500        if (!arrayToBignum(env, keyJavaBytes, &keyRef)) {
1501            return 0;
1502        }
1503        key.reset(keyRef);
1504    }
1505
1506    Unique_EC_KEY eckey(EC_KEY_new());
1507    if (eckey.get() == NULL) {
1508        jniThrowRuntimeException(env, "EC_KEY_new failed");
1509        return 0;
1510    }
1511
1512    if (EC_KEY_set_group(eckey.get(), group) != 1) {
1513        JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey,
1514                keyJavaBytes);
1515        throwExceptionIfNecessary(env, "EC_KEY_set_group");
1516        return 0;
1517    }
1518
1519    if (pubkey != NULL) {
1520        if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) {
1521            JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
1522                    pubkey, keyJavaBytes);
1523            throwExceptionIfNecessary(env, "EC_KEY_set_public_key");
1524            return 0;
1525        }
1526    }
1527
1528    if (key.get() != NULL) {
1529        if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) {
1530            JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
1531                    pubkey, keyJavaBytes);
1532            throwExceptionIfNecessary(env, "EC_KEY_set_private_key");
1533            return 0;
1534        }
1535        if (pubkey == NULL) {
1536            Unique_EC_POINT calcPubkey(EC_POINT_new(group));
1537            if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), NULL, NULL, NULL)) {
1538                JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calulate public key", group,
1539                        pubkey, keyJavaBytes);
1540                throwExceptionIfNecessary(env, "EC_KEY_set_private_key");
1541                return 0;
1542            }
1543            EC_KEY_set_public_key(eckey.get(), calcPubkey.get());
1544        }
1545    }
1546
1547    if (!EC_KEY_check_key(eckey.get())) {
1548        JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey, keyJavaBytes);
1549        throwExceptionIfNecessary(env, "EC_KEY_check_key");
1550        return 0;
1551    }
1552
1553    Unique_EVP_PKEY pkey(EVP_PKEY_new());
1554    if (pkey.get() == NULL) {
1555        JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
1556        throwExceptionIfNecessary(env, "EVP_PKEY_new failed");
1557        return 0;
1558    }
1559    if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
1560        JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
1561        jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
1562        return 0;
1563    }
1564    OWNERSHIP_TRANSFERRED(eckey);
1565
1566    JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get());
1567    return reinterpret_cast<uintptr_t>(pkey.release());
1568}
1569
1570static jlong NativeCrypto_EVP_PKEY_new_mac_key(JNIEnv* env, jclass, jint pkeyType,
1571        jbyteArray keyJavaBytes)
1572{
1573    JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p)", pkeyType, keyJavaBytes);
1574
1575    ScopedByteArrayRO key(env, keyJavaBytes);
1576    if (key.get() == NULL) {
1577        return 0;
1578    }
1579
1580    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(key.get());
1581    Unique_EVP_PKEY pkey(EVP_PKEY_new_mac_key(pkeyType, (ENGINE *) NULL, tmp, key.size()));
1582    if (pkey.get() == NULL) {
1583        JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => threw error", pkeyType, keyJavaBytes);
1584        throwExceptionIfNecessary(env, "ENGINE_load_private_key");
1585        return 0;
1586    }
1587
1588    JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => %p", pkeyType, keyJavaBytes, pkey.get());
1589    return reinterpret_cast<uintptr_t>(pkey.release());
1590}
1591
1592static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jlong pkeyRef) {
1593    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1594    JNI_TRACE("EVP_PKEY_type(%p)", pkey);
1595
1596    if (pkey == NULL) {
1597        jniThrowNullPointerException(env, NULL);
1598        return -1;
1599    }
1600
1601    int result = EVP_PKEY_type(pkey->type);
1602    JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result);
1603    return result;
1604}
1605
1606/**
1607 * private static native int EVP_PKEY_size(int pkey);
1608 */
1609static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jlong pkeyRef) {
1610    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1611    JNI_TRACE("EVP_PKEY_size(%p)", pkey);
1612
1613    if (pkey == NULL) {
1614        jniThrowNullPointerException(env, NULL);
1615        return -1;
1616    }
1617
1618    int result = EVP_PKEY_size(pkey);
1619    JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result);
1620    return result;
1621}
1622
1623static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jlong pkeyRef) {
1624    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1625    JNI_TRACE("EVP_PKEY_print_public(%p)", pkey);
1626
1627    if (pkey == NULL) {
1628        jniThrowNullPointerException(env, "pkey == null");
1629        return NULL;
1630    }
1631
1632    Unique_BIO buffer(BIO_new(BIO_s_mem()));
1633    if (buffer.get() == NULL) {
1634        jniThrowOutOfMemory(env, "Unable to allocate BIO");
1635        return NULL;
1636    }
1637
1638    if (EVP_PKEY_print_public(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) {
1639        throwExceptionIfNecessary(env, "EVP_PKEY_print_public");
1640        return NULL;
1641    }
1642    // Null terminate this
1643    BIO_write(buffer.get(), "\0", 1);
1644
1645    char *tmp;
1646    BIO_get_mem_data(buffer.get(), &tmp);
1647    jstring description = env->NewStringUTF(tmp);
1648
1649    JNI_TRACE("EVP_PKEY_print_public(%p) => \"%s\"", pkey, tmp);
1650    return description;
1651}
1652
1653static jstring NativeCrypto_EVP_PKEY_print_private(JNIEnv* env, jclass, jlong pkeyRef) {
1654    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1655    JNI_TRACE("EVP_PKEY_print_private(%p)", pkey);
1656
1657    if (pkey == NULL) {
1658        jniThrowNullPointerException(env, "pkey == null");
1659        return NULL;
1660    }
1661
1662    Unique_BIO buffer(BIO_new(BIO_s_mem()));
1663    if (buffer.get() == NULL) {
1664        jniThrowOutOfMemory(env, "Unable to allocate BIO");
1665        return NULL;
1666    }
1667
1668    if (EVP_PKEY_print_private(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) {
1669        throwExceptionIfNecessary(env, "EVP_PKEY_print_private");
1670        return NULL;
1671    }
1672    // Null terminate this
1673    BIO_write(buffer.get(), "\0", 1);
1674
1675    char *tmp;
1676    BIO_get_mem_data(buffer.get(), &tmp);
1677    jstring description = env->NewStringUTF(tmp);
1678
1679    JNI_TRACE("EVP_PKEY_print_private(%p) => \"%s\"", pkey, tmp);
1680    return description;
1681}
1682
1683static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, jlong pkeyRef) {
1684    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1685    JNI_TRACE("EVP_PKEY_free(%p)", pkey);
1686
1687    if (pkey != NULL) {
1688        EVP_PKEY_free(pkey);
1689    }
1690}
1691
1692static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jlong pkey1Ref, jlong pkey2Ref) {
1693    EVP_PKEY* pkey1 = reinterpret_cast<EVP_PKEY*>(pkey1Ref);
1694    EVP_PKEY* pkey2 = reinterpret_cast<EVP_PKEY*>(pkey2Ref);
1695    JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1, pkey2);
1696
1697    if (pkey1 == NULL) {
1698        JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey1 == NULL", pkey1, pkey2);
1699        jniThrowNullPointerException(env, "pkey1 == NULL");
1700        return -1;
1701    } else if (pkey2 == NULL) {
1702        JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey2 == NULL", pkey1, pkey2);
1703        jniThrowNullPointerException(env, "pkey2 == NULL");
1704        return -1;
1705    }
1706
1707    int result = EVP_PKEY_cmp(pkey1, pkey2);
1708    JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result);
1709    return result;
1710}
1711
1712/*
1713 * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[])
1714 */
1715static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jlong pkeyRef) {
1716    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1717    JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey);
1718
1719    if (pkey == NULL) {
1720        jniThrowNullPointerException(env, NULL);
1721        return NULL;
1722    }
1723
1724    Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey));
1725    if (pkcs8.get() == NULL) {
1726        throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO");
1727        JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey);
1728        return NULL;
1729    }
1730
1731    return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO>(env, pkcs8.get());
1732}
1733
1734/*
1735 * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[])
1736 */
1737static jlong NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
1738    JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes);
1739
1740    ScopedByteArrayRO bytes(env, keyJavaBytes);
1741    if (bytes.get() == NULL) {
1742        JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes);
1743        return 0;
1744    }
1745
1746    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
1747    Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, bytes.size()));
1748    if (pkcs8.get() == NULL) {
1749        throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
1750        JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes);
1751        return 0;
1752    }
1753
1754    Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
1755    if (pkey.get() == NULL) {
1756        throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
1757        JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes);
1758        return 0;
1759    }
1760
1761    JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get());
1762    return reinterpret_cast<uintptr_t>(pkey.release());
1763}
1764
1765/*
1766 * static native byte[] i2d_PUBKEY(int)
1767 */
1768static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jlong pkeyRef) {
1769    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1770    JNI_TRACE("i2d_PUBKEY(%p)", pkey);
1771    return ASN1ToByteArray<EVP_PKEY, i2d_PUBKEY>(env, pkey);
1772}
1773
1774/*
1775 * static native int d2i_PUBKEY(byte[])
1776 */
1777static jlong NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) {
1778    JNI_TRACE("d2i_PUBKEY(%p)", javaBytes);
1779
1780    ScopedByteArrayRO bytes(env, javaBytes);
1781    if (bytes.get() == NULL) {
1782        JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes);
1783        return 0;
1784    }
1785
1786    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
1787    Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, bytes.size()));
1788    if (pkey.get() == NULL) {
1789        JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes);
1790        throwExceptionIfNecessary(env, "d2i_PUBKEY");
1791        return 0;
1792    }
1793
1794    return reinterpret_cast<uintptr_t>(pkey.release());
1795}
1796
1797/*
1798 * public static native int RSA_generate_key(int modulusBits, byte[] publicExponent);
1799 */
1800static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits,
1801        jbyteArray publicExponent) {
1802    JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent);
1803
1804    BIGNUM* eRef;
1805    if (!arrayToBignum(env, publicExponent, &eRef)) {
1806        return 0;
1807    }
1808    Unique_BIGNUM e(eRef);
1809
1810    Unique_RSA rsa(RSA_new());
1811    if (rsa.get() == NULL) {
1812        jniThrowOutOfMemory(env, "Unable to allocate RSA key");
1813        return 0;
1814    }
1815
1816    if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), NULL) < 0) {
1817        throwExceptionIfNecessary(env, "RSA_generate_key_ex");
1818        return 0;
1819    }
1820
1821    Unique_EVP_PKEY pkey(EVP_PKEY_new());
1822    if (pkey.get() == NULL) {
1823        jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
1824        return 0;
1825    }
1826
1827    if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
1828        jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
1829        return 0;
1830    }
1831
1832    OWNERSHIP_TRANSFERRED(rsa);
1833    JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get());
1834    return reinterpret_cast<uintptr_t>(pkey.release());
1835}
1836
1837static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jlong pkeyRef) {
1838    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1839    JNI_TRACE("RSA_size(%p)", pkey);
1840
1841    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
1842    if (rsa.get() == NULL) {
1843        jniThrowRuntimeException(env, "RSA_size failed");
1844        return 0;
1845    }
1846
1847    return static_cast<jint>(RSA_size(rsa.get()));
1848}
1849
1850typedef int RSACryptOperation(int flen, const unsigned char* from, unsigned char* to, RSA* rsa,
1851                              int padding);
1852
1853static jint RSA_crypt_operation(RSACryptOperation operation,
1854        const char* caller __attribute__ ((unused)), JNIEnv* env, jint flen,
1855        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
1856    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1857    JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey);
1858
1859    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
1860    if (rsa.get() == NULL) {
1861        return -1;
1862    }
1863
1864    ScopedByteArrayRO from(env, fromJavaBytes);
1865    if (from.get() == NULL) {
1866        return -1;
1867    }
1868
1869    ScopedByteArrayRW to(env, toJavaBytes);
1870    if (to.get() == NULL) {
1871        return -1;
1872    }
1873
1874    int resultSize = operation(static_cast<int>(flen),
1875            reinterpret_cast<const unsigned char*>(from.get()),
1876            reinterpret_cast<unsigned char*>(to.get()), rsa.get(), padding);
1877    if (resultSize == -1) {
1878        JNI_TRACE("%s => failed", caller);
1879        throwExceptionIfNecessary(env, "RSA_crypt_operation");
1880        return -1;
1881    }
1882
1883    JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey,
1884              resultSize);
1885    return static_cast<jint>(resultSize);
1886}
1887
1888static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen,
1889        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
1890    return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__,
1891                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
1892}
1893static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen,
1894        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
1895    return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__,
1896                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
1897}
1898static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen,
1899        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
1900    return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__,
1901                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
1902}
1903static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen,
1904        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
1905    return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__,
1906                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
1907}
1908
1909/*
1910 * public static native byte[][] get_RSA_public_params(int);
1911 */
1912static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jlong pkeyRef) {
1913    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1914    JNI_TRACE("get_RSA_public_params(%p)", pkey);
1915
1916    if (pkey == NULL) {
1917        jniThrowNullPointerException(env, "pkey == null");
1918        return 0;
1919    }
1920
1921    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
1922    if (rsa.get() == NULL) {
1923        throwExceptionIfNecessary(env, "get_RSA_public_params failed");
1924        return 0;
1925    }
1926
1927    jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL);
1928    if (joa == NULL) {
1929        return NULL;
1930    }
1931
1932    jbyteArray n = bignumToArray(env, rsa->n, "n");
1933    if (env->ExceptionCheck()) {
1934        return NULL;
1935    }
1936    env->SetObjectArrayElement(joa, 0, n);
1937
1938    jbyteArray e = bignumToArray(env, rsa->e, "e");
1939    if (env->ExceptionCheck()) {
1940        return NULL;
1941    }
1942    env->SetObjectArrayElement(joa, 1, e);
1943
1944    return joa;
1945}
1946
1947/*
1948 * public static native byte[][] get_RSA_private_params(int);
1949 */
1950static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jlong pkeyRef) {
1951    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
1952    JNI_TRACE("get_RSA_public_params(%p)", pkey);
1953
1954    if (pkey == NULL) {
1955        jniThrowNullPointerException(env, "pkey == null");
1956        return 0;
1957    }
1958
1959    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
1960    if (rsa.get() == NULL) {
1961        throwExceptionIfNecessary(env, "get_RSA_public_params failed");
1962        return 0;
1963    }
1964
1965    jobjectArray joa = env->NewObjectArray(8, byteArrayClass, NULL);
1966    if (joa == NULL) {
1967        return NULL;
1968    }
1969
1970    jbyteArray n = bignumToArray(env, rsa->n, "n");
1971    if (env->ExceptionCheck()) {
1972        return NULL;
1973    }
1974    env->SetObjectArrayElement(joa, 0, n);
1975
1976    if (rsa->e != NULL) {
1977        jbyteArray e = bignumToArray(env, rsa->e, "e");
1978        if (env->ExceptionCheck()) {
1979            return NULL;
1980        }
1981        env->SetObjectArrayElement(joa, 1, e);
1982    }
1983
1984    if (rsa->d != NULL) {
1985        jbyteArray d = bignumToArray(env, rsa->d, "d");
1986        if (env->ExceptionCheck()) {
1987            return NULL;
1988        }
1989        env->SetObjectArrayElement(joa, 2, d);
1990    }
1991
1992    if (rsa->p != NULL) {
1993        jbyteArray p = bignumToArray(env, rsa->p, "p");
1994        if (env->ExceptionCheck()) {
1995            return NULL;
1996        }
1997        env->SetObjectArrayElement(joa, 3, p);
1998    }
1999
2000    if (rsa->q != NULL) {
2001        jbyteArray q = bignumToArray(env, rsa->q, "q");
2002        if (env->ExceptionCheck()) {
2003            return NULL;
2004        }
2005        env->SetObjectArrayElement(joa, 4, q);
2006    }
2007
2008    if (rsa->dmp1 != NULL) {
2009        jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1");
2010        if (env->ExceptionCheck()) {
2011            return NULL;
2012        }
2013        env->SetObjectArrayElement(joa, 5, dmp1);
2014    }
2015
2016    if (rsa->dmq1 != NULL) {
2017        jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1");
2018        if (env->ExceptionCheck()) {
2019            return NULL;
2020        }
2021        env->SetObjectArrayElement(joa, 6, dmq1);
2022    }
2023
2024    if (rsa->iqmp != NULL) {
2025        jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp");
2026        if (env->ExceptionCheck()) {
2027            return NULL;
2028        }
2029        env->SetObjectArrayElement(joa, 7, iqmp);
2030    }
2031
2032    return joa;
2033}
2034
2035/*
2036 * public static native int DSA_generate_key(int, byte[]);
2037 */
2038static jlong NativeCrypto_DSA_generate_key(JNIEnv* env, jclass, jint primeBits,
2039        jbyteArray seedJavaBytes, jbyteArray gBytes, jbyteArray pBytes, jbyteArray qBytes) {
2040    JNI_TRACE("DSA_generate_key(%d, %p, %p, %p, %p)", primeBits, seedJavaBytes,
2041            gBytes, pBytes, qBytes);
2042
2043    UniquePtr<unsigned char[]> seedPtr;
2044    unsigned long seedSize = 0;
2045    if (seedJavaBytes != NULL) {
2046        ScopedByteArrayRO seed(env, seedJavaBytes);
2047        if (seed.get() == NULL) {
2048            return 0;
2049        }
2050
2051        seedSize = seed.size();
2052        seedPtr.reset(new unsigned char[seedSize]);
2053
2054        memcpy(seedPtr.get(), seed.get(), seedSize);
2055    }
2056
2057    Unique_DSA dsa(DSA_new());
2058    if (dsa.get() == NULL) {
2059        JNI_TRACE("DSA_generate_key failed");
2060        jniThrowOutOfMemory(env, "Unable to allocate DSA key");
2061        freeOpenSslErrorState();
2062        return 0;
2063    }
2064
2065    if (gBytes != NULL && pBytes != NULL && qBytes != NULL) {
2066        JNI_TRACE("DSA_generate_key parameters specified");
2067
2068        if (!arrayToBignum(env, gBytes, &dsa->g)) {
2069            return 0;
2070        }
2071
2072        if (!arrayToBignum(env, pBytes, &dsa->p)) {
2073            return 0;
2074        }
2075
2076        if (!arrayToBignum(env, qBytes, &dsa->q)) {
2077            return 0;
2078        }
2079    } else {
2080        JNI_TRACE("DSA_generate_key generating parameters");
2081
2082        if (!DSA_generate_parameters_ex(dsa.get(), primeBits, seedPtr.get(), seedSize, NULL, NULL, NULL)) {
2083            JNI_TRACE("DSA_generate_key => param generation failed");
2084            throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_parameters_ex failed");
2085            return 0;
2086        }
2087    }
2088
2089    if (!DSA_generate_key(dsa.get())) {
2090        JNI_TRACE("DSA_generate_key failed");
2091        throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed");
2092        return 0;
2093    }
2094
2095    Unique_EVP_PKEY pkey(EVP_PKEY_new());
2096    if (pkey.get() == NULL) {
2097        JNI_TRACE("DSA_generate_key failed");
2098        jniThrowRuntimeException(env, "NativeCrypto_DSA_generate_key failed");
2099        freeOpenSslErrorState();
2100        return 0;
2101    }
2102
2103    if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
2104        JNI_TRACE("DSA_generate_key failed");
2105        throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed");
2106        return 0;
2107    }
2108
2109    OWNERSHIP_TRANSFERRED(dsa);
2110    JNI_TRACE("DSA_generate_key(n=%d, e=%p) => %p", primeBits, seedPtr.get(), pkey.get());
2111    return reinterpret_cast<uintptr_t>(pkey.release());
2112}
2113
2114/*
2115 * public static native byte[][] get_DSA_params(int);
2116 */
2117static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jlong pkeyRef) {
2118    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
2119    JNI_TRACE("get_DSA_params(%p)", pkey);
2120
2121    Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey));
2122    if (dsa.get() == NULL) {
2123        throwExceptionIfNecessary(env, "get_DSA_params failed");
2124        return 0;
2125    }
2126
2127    jobjectArray joa = env->NewObjectArray(5, byteArrayClass, NULL);
2128    if (joa == NULL) {
2129        return NULL;
2130    }
2131
2132    if (dsa->g != NULL) {
2133        jbyteArray g = bignumToArray(env, dsa->g, "g");
2134        if (env->ExceptionCheck()) {
2135            return NULL;
2136        }
2137        env->SetObjectArrayElement(joa, 0, g);
2138    }
2139
2140    if (dsa->p != NULL) {
2141        jbyteArray p = bignumToArray(env, dsa->p, "p");
2142        if (env->ExceptionCheck()) {
2143            return NULL;
2144        }
2145        env->SetObjectArrayElement(joa, 1, p);
2146    }
2147
2148    if (dsa->q != NULL) {
2149        jbyteArray q = bignumToArray(env, dsa->q, "q");
2150        if (env->ExceptionCheck()) {
2151            return NULL;
2152        }
2153        env->SetObjectArrayElement(joa, 2, q);
2154    }
2155
2156    if (dsa->pub_key != NULL) {
2157        jbyteArray pub_key = bignumToArray(env, dsa->pub_key, "pub_key");
2158        if (env->ExceptionCheck()) {
2159            return NULL;
2160        }
2161        env->SetObjectArrayElement(joa, 3, pub_key);
2162    }
2163
2164    if (dsa->priv_key != NULL) {
2165        jbyteArray priv_key = bignumToArray(env, dsa->priv_key, "priv_key");
2166        if (env->ExceptionCheck()) {
2167            return NULL;
2168        }
2169        env->SetObjectArrayElement(joa, 4, priv_key);
2170    }
2171
2172    return joa;
2173}
2174
2175#define EC_CURVE_GFP 1
2176#define EC_CURVE_GF2M 2
2177
2178/**
2179 * Return group type or 0 if unknown group.
2180 * EC_GROUP_GFP or EC_GROUP_GF2M
2181 */
2182static int get_EC_GROUP_type(const EC_GROUP* group)
2183{
2184    const EC_METHOD* method = EC_GROUP_method_of(group);
2185    if (method == EC_GFp_nist_method()
2186                || method == EC_GFp_mont_method()
2187                || method == EC_GFp_simple_method()) {
2188        return EC_CURVE_GFP;
2189    } else if (method == EC_GF2m_simple_method()) {
2190        return EC_CURVE_GF2M;
2191    }
2192
2193    return 0;
2194}
2195
2196static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava)
2197{
2198    JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava);
2199
2200    ScopedUtfChars curveName(env, curveNameJava);
2201    if (curveName.c_str() == NULL) {
2202        return 0;
2203    }
2204    JNI_TRACE("EC_GROUP_new_by_curve_name(%s)", curveName.c_str());
2205
2206    int nid = OBJ_sn2nid(curveName.c_str());
2207    if (nid == NID_undef) {
2208        JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID name", curveName.c_str());
2209        return 0;
2210    }
2211
2212    EC_GROUP* group = EC_GROUP_new_by_curve_name(nid);
2213    if (group == NULL) {
2214        JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID %d", curveName.c_str(), nid);
2215        freeOpenSslErrorState();
2216        return 0;
2217    }
2218
2219    JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => %p", curveName.c_str(), group);
2220    return reinterpret_cast<uintptr_t>(group);
2221}
2222
2223static void NativeCrypto_EC_GROUP_set_asn1_flag(JNIEnv* env, jclass, jlong groupRef,
2224        jint flag)
2225{
2226    EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
2227    JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d)", group, flag);
2228
2229    if (group == NULL) {
2230        JNI_TRACE("EC_GROUP_set_asn1_flag => group == NULL");
2231        jniThrowNullPointerException(env, "group == NULL");
2232        return;
2233    }
2234
2235    EC_GROUP_set_asn1_flag(group, flag);
2236    JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d) => success", group, flag);
2237}
2238
2239static void NativeCrypto_EC_GROUP_set_point_conversion_form(JNIEnv* env, jclass,
2240        jlong groupRef, jint form)
2241{
2242    EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
2243    JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d)", group, form);
2244
2245    if (group == NULL) {
2246        JNI_TRACE("EC_GROUP_set_point_conversion_form => group == NULL");
2247        jniThrowNullPointerException(env, "group == NULL");
2248        return;
2249    }
2250
2251    EC_GROUP_set_point_conversion_form(group, static_cast<point_conversion_form_t>(form));
2252    JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d) => success", group, form);
2253}
2254
2255static jlong NativeCrypto_EC_GROUP_new_curve(JNIEnv* env, jclass, jint type, jbyteArray pJava,
2256        jbyteArray aJava, jbyteArray bJava)
2257{
2258    JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p)", type, pJava, aJava, bJava);
2259
2260    BIGNUM* pRef;
2261    if (!arrayToBignum(env, pJava, &pRef)) {
2262        return 0;
2263    }
2264    Unique_BIGNUM p(pRef);
2265
2266    BIGNUM* aRef;
2267    if (!arrayToBignum(env, aJava, &aRef)) {
2268        return 0;
2269    }
2270    Unique_BIGNUM a(aRef);
2271
2272    BIGNUM* bRef;
2273    if (!arrayToBignum(env, bJava, &bRef)) {
2274        return 0;
2275    }
2276    Unique_BIGNUM b(bRef);
2277
2278    EC_GROUP* group;
2279    switch (type) {
2280    case EC_CURVE_GFP:
2281        group = EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), (BN_CTX*) NULL);
2282        break;
2283    case EC_CURVE_GF2M:
2284        group = EC_GROUP_new_curve_GF2m(p.get(), a.get(), b.get(), (BN_CTX*) NULL);
2285        break;
2286    default:
2287        jniThrowRuntimeException(env, "invalid group");
2288        return 0;
2289    }
2290
2291    if (group == NULL) {
2292        throwExceptionIfNecessary(env, "EC_GROUP_new_curve");
2293    }
2294
2295    JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p) => %p", type, pJava, aJava, bJava, group);
2296    return reinterpret_cast<uintptr_t>(group);
2297}
2298
2299static jlong NativeCrypto_EC_GROUP_dup(JNIEnv* env, jclass, jlong groupRef) {
2300    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2301    JNI_TRACE("EC_GROUP_dup(%p)", group);
2302
2303    if (group == NULL) {
2304         JNI_TRACE("EC_GROUP_dup => group == NULL");
2305         jniThrowNullPointerException(env, "group == NULL");
2306         return 0;
2307     }
2308
2309     EC_GROUP* groupDup = EC_GROUP_dup(group);
2310     JNI_TRACE("EC_GROUP_dup(%p) => %p", group, groupDup);
2311     return reinterpret_cast<uintptr_t>(groupDup);
2312}
2313
2314static jstring NativeCrypto_EC_GROUP_get_curve_name(JNIEnv* env, jclass, jlong groupRef) {
2315    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2316    JNI_TRACE("EC_GROUP_get_curve_name(%p)", group);
2317
2318    if (group == NULL) {
2319        JNI_TRACE("EC_GROUP_get_curve_name => group == NULL");
2320        jniThrowNullPointerException(env, "group == NULL");
2321        return 0;
2322    }
2323
2324    int nid = EC_GROUP_get_curve_name(group);
2325    if (nid == NID_undef) {
2326        JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group);
2327        return NULL;
2328    }
2329
2330    const char* shortName = OBJ_nid2sn(nid);
2331    JNI_TRACE("EC_GROUP_get_curve_name(%p) => \"%s\"", group, shortName);
2332    return env->NewStringUTF(shortName);
2333}
2334
2335static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jlong groupRef)
2336{
2337    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2338    JNI_TRACE("EC_GROUP_get_curve(%p)", group);
2339
2340    Unique_BIGNUM p(BN_new());
2341    Unique_BIGNUM a(BN_new());
2342    Unique_BIGNUM b(BN_new());
2343
2344    int ret;
2345    switch (get_EC_GROUP_type(group)) {
2346    case EC_CURVE_GFP:
2347        ret = EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), (BN_CTX*) NULL);
2348        break;
2349    case EC_CURVE_GF2M:
2350        ret = EC_GROUP_get_curve_GF2m(group, p.get(), a.get(), b.get(), (BN_CTX*)NULL);
2351        break;
2352    default:
2353        jniThrowRuntimeException(env, "invalid group");
2354        return NULL;
2355    }
2356    if (ret != 1) {
2357        throwExceptionIfNecessary(env, "EC_GROUP_get_curve");
2358        return NULL;
2359    }
2360
2361    jobjectArray joa = env->NewObjectArray(3, byteArrayClass, NULL);
2362    if (joa == NULL) {
2363        return NULL;
2364    }
2365
2366    jbyteArray pArray = bignumToArray(env, p.get(), "p");
2367    if (env->ExceptionCheck()) {
2368        return NULL;
2369    }
2370    env->SetObjectArrayElement(joa, 0, pArray);
2371
2372    jbyteArray aArray = bignumToArray(env, a.get(), "a");
2373    if (env->ExceptionCheck()) {
2374        return NULL;
2375    }
2376    env->SetObjectArrayElement(joa, 1, aArray);
2377
2378    jbyteArray bArray = bignumToArray(env, b.get(), "b");
2379    if (env->ExceptionCheck()) {
2380        return NULL;
2381    }
2382    env->SetObjectArrayElement(joa, 2, bArray);
2383
2384    JNI_TRACE("EC_GROUP_get_curve(%p) => %p", group, joa);
2385    return joa;
2386}
2387
2388static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jlong groupRef)
2389{
2390    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2391    JNI_TRACE("EC_GROUP_get_order(%p)", group);
2392
2393    Unique_BIGNUM order(BN_new());
2394    if (order.get() == NULL) {
2395        JNI_TRACE("EC_GROUP_get_order(%p) => can't create BN", group);
2396        jniThrowOutOfMemory(env, "BN_new");
2397        return NULL;
2398    }
2399
2400    if (EC_GROUP_get_order(group, order.get(), NULL) != 1) {
2401        JNI_TRACE("EC_GROUP_get_order(%p) => threw error", group);
2402        throwExceptionIfNecessary(env, "EC_GROUP_get_order");
2403        return NULL;
2404    }
2405
2406    jbyteArray orderArray = bignumToArray(env, order.get(), "order");
2407    if (env->ExceptionCheck()) {
2408        return NULL;
2409    }
2410
2411    JNI_TRACE("EC_GROUP_get_order(%p) => %p", group, orderArray);
2412    return orderArray;
2413}
2414
2415static jint NativeCrypto_EC_GROUP_get_degree(JNIEnv* env, jclass, jlong groupRef)
2416{
2417    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2418    JNI_TRACE("EC_GROUP_get_degree(%p)", group);
2419
2420    jint degree = EC_GROUP_get_degree(group);
2421    if (degree == 0) {
2422      JNI_TRACE("EC_GROUP_get_degree(%p) => unsupported", group);
2423      jniThrowRuntimeException(env, "not supported");
2424      return 0;
2425    }
2426
2427    JNI_TRACE("EC_GROUP_get_degree(%p) => %d", group, degree);
2428    return degree;
2429}
2430
2431static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jlong groupRef)
2432{
2433    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2434    JNI_TRACE("EC_GROUP_get_cofactor(%p)", group);
2435
2436    Unique_BIGNUM cofactor(BN_new());
2437    if (cofactor.get() == NULL) {
2438        JNI_TRACE("EC_GROUP_get_cofactor(%p) => can't create BN", group);
2439        jniThrowOutOfMemory(env, "BN_new");
2440        return NULL;
2441    }
2442
2443    if (EC_GROUP_get_cofactor(group, cofactor.get(), NULL) != 1) {
2444        JNI_TRACE("EC_GROUP_get_cofactor(%p) => threw error", group);
2445        throwExceptionIfNecessary(env, "EC_GROUP_get_cofactor");
2446        return NULL;
2447    }
2448
2449    jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor");
2450    if (env->ExceptionCheck()) {
2451        return NULL;
2452    }
2453
2454    JNI_TRACE("EC_GROUP_get_cofactor(%p) => %p", group, cofactorArray);
2455    return cofactorArray;
2456}
2457
2458static jint NativeCrypto_get_EC_GROUP_type(JNIEnv* env, jclass, jlong groupRef)
2459{
2460    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2461    JNI_TRACE("get_EC_GROUP_type(%p)", group);
2462
2463    int type = get_EC_GROUP_type(group);
2464    if (type == 0) {
2465        JNI_TRACE("get_EC_GROUP_type(%p) => curve type", group);
2466        jniThrowRuntimeException(env, "unknown curve type");
2467    } else {
2468        JNI_TRACE("get_EC_GROUP_type(%p) => %d", group, type);
2469    }
2470    return type;
2471}
2472
2473static void NativeCrypto_EC_GROUP_clear_free(JNIEnv* env, jclass, jlong groupRef)
2474{
2475    EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
2476    JNI_TRACE("EC_GROUP_clear_free(%p)", group);
2477
2478    if (group == NULL) {
2479        JNI_TRACE("EC_GROUP_clear_free => group == NULL");
2480        jniThrowNullPointerException(env, "group == NULL");
2481        return;
2482    }
2483
2484    EC_GROUP_clear_free(group);
2485    JNI_TRACE("EC_GROUP_clear_free(%p) => success", group);
2486}
2487
2488static jboolean NativeCrypto_EC_GROUP_cmp(JNIEnv* env, jclass, jlong group1Ref, jlong group2Ref)
2489{
2490    const EC_GROUP* group1 = reinterpret_cast<const EC_GROUP*>(group1Ref);
2491    const EC_GROUP* group2 = reinterpret_cast<const EC_GROUP*>(group2Ref);
2492    JNI_TRACE("EC_GROUP_cmp(%p, %p)", group1, group2);
2493
2494    if (group1 == NULL || group2 == NULL) {
2495        JNI_TRACE("EC_GROUP_cmp(%p, %p) => group1 == null || group2 == null", group1, group2);
2496        jniThrowNullPointerException(env, "group1 == null || group2 == null");
2497        return false;
2498    }
2499
2500    int ret = EC_GROUP_cmp(group1, group2, (BN_CTX*)NULL);
2501
2502    JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", group1, group2, ret);
2503    return ret == 0;
2504}
2505
2506static void NativeCrypto_EC_GROUP_set_generator(JNIEnv* env, jclass, jlong groupRef, jlong pointRef, jbyteArray njavaBytes, jbyteArray hjavaBytes)
2507{
2508    EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
2509    const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef);
2510    JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p)", group, point, njavaBytes, hjavaBytes);
2511
2512    if (group == NULL || point == NULL) {
2513        JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => group == null || point == null",
2514                group, point, njavaBytes, hjavaBytes);
2515        jniThrowNullPointerException(env, "group == null || point == null");
2516        return;
2517    }
2518
2519    BIGNUM* nRef;
2520    if (!arrayToBignum(env, njavaBytes, &nRef)) {
2521        return;
2522    }
2523    Unique_BIGNUM n(nRef);
2524
2525    BIGNUM* hRef;
2526    if (!arrayToBignum(env, hjavaBytes, &hRef)) {
2527        return;
2528    }
2529    Unique_BIGNUM h(hRef);
2530
2531    int ret = EC_GROUP_set_generator(group, point, n.get(), h.get());
2532    if (ret == 0) {
2533        throwExceptionIfNecessary(env, "EC_GROUP_set_generator");
2534    }
2535
2536    JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => %d", group, point, njavaBytes, hjavaBytes, ret);
2537}
2538
2539static jlong NativeCrypto_EC_GROUP_get_generator(JNIEnv* env, jclass, jlong groupRef)
2540{
2541    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2542    JNI_TRACE("EC_GROUP_get_generator(%p)", group);
2543
2544    if (group == NULL) {
2545        JNI_TRACE("EC_POINT_get_generator(%p) => group == null", group);
2546        jniThrowNullPointerException(env, "group == null");
2547        return 0;
2548    }
2549
2550    const EC_POINT* generator = EC_GROUP_get0_generator(group);
2551
2552    Unique_EC_POINT dup(EC_POINT_dup(generator, group));
2553    if (dup.get() == NULL) {
2554        JNI_TRACE("EC_GROUP_get_generator(%p) => oom error", group);
2555        jniThrowOutOfMemory(env, "unable to dupe generator");
2556        return 0;
2557    }
2558
2559    JNI_TRACE("EC_GROUP_get_generator(%p) => %p", group, dup.get());
2560    return reinterpret_cast<uintptr_t>(dup.release());
2561}
2562
2563static jlong NativeCrypto_EC_POINT_new(JNIEnv* env, jclass, jlong groupRef)
2564{
2565    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2566    JNI_TRACE("EC_POINT_new(%p)", group);
2567
2568    if (group == NULL) {
2569        JNI_TRACE("EC_POINT_new(%p) => group == null", group);
2570        jniThrowNullPointerException(env, "group == null");
2571        return 0;
2572    }
2573
2574    EC_POINT* point = EC_POINT_new(group);
2575    if (point == NULL) {
2576        jniThrowOutOfMemory(env, "Unable create an EC_POINT");
2577        return 0;
2578    }
2579
2580    return reinterpret_cast<uintptr_t>(point);
2581}
2582
2583static void NativeCrypto_EC_POINT_clear_free(JNIEnv* env, jclass, jlong groupRef) {
2584    EC_POINT* group = reinterpret_cast<EC_POINT*>(groupRef);
2585    JNI_TRACE("EC_POINT_clear_free(%p)", group);
2586
2587    if (group == NULL) {
2588        JNI_TRACE("EC_POINT_clear_free => group == NULL");
2589        jniThrowNullPointerException(env, "group == NULL");
2590        return;
2591    }
2592
2593    EC_POINT_clear_free(group);
2594    JNI_TRACE("EC_POINT_clear_free(%p) => success", group);
2595}
2596
2597static jboolean NativeCrypto_EC_POINT_cmp(JNIEnv* env, jclass, jlong groupRef, jlong point1Ref, jlong point2Ref)
2598{
2599    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2600    const EC_POINT* point1 = reinterpret_cast<const EC_POINT*>(point1Ref);
2601    const EC_POINT* point2 = reinterpret_cast<const EC_POINT*>(point2Ref);
2602    JNI_TRACE("EC_POINT_cmp(%p, %p, %p)", group, point1, point2);
2603
2604    if (group == NULL || point1 == NULL || point2 == NULL) {
2605        JNI_TRACE("EC_POINT_cmp(%p, %p, %p) => group == null || point1 == null || point2 == null",
2606                group, point1, point2);
2607        jniThrowNullPointerException(env, "group == null || point1 == null || point2 == null");
2608        return false;
2609    }
2610
2611    int ret = EC_POINT_cmp(group, point1, point2, (BN_CTX*)NULL);
2612
2613    JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", point1, point2, ret);
2614    return ret == 0;
2615}
2616
2617static void NativeCrypto_EC_POINT_set_affine_coordinates(JNIEnv* env, jclass,
2618        jlong groupRef, jlong pointRef, jbyteArray xjavaBytes, jbyteArray yjavaBytes)
2619{
2620    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2621    EC_POINT* point = reinterpret_cast<EC_POINT*>(pointRef);
2622    JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p)", group, point, xjavaBytes,
2623            yjavaBytes);
2624
2625    if (group == NULL || point == NULL) {
2626        JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => group == null || point == null",
2627                group, point, xjavaBytes, yjavaBytes);
2628        jniThrowNullPointerException(env, "group == null || point == null");
2629        return;
2630    }
2631
2632    BIGNUM* xRef;
2633    if (!arrayToBignum(env, xjavaBytes, &xRef)) {
2634        return;
2635    }
2636    Unique_BIGNUM x(xRef);
2637
2638    BIGNUM* yRef;
2639    if (!arrayToBignum(env, yjavaBytes, &yRef)) {
2640        return;
2641    }
2642    Unique_BIGNUM y(yRef);
2643
2644    int ret;
2645    switch (get_EC_GROUP_type(group)) {
2646    case EC_CURVE_GFP:
2647        ret = EC_POINT_set_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL);
2648        break;
2649    case EC_CURVE_GF2M:
2650        ret = EC_POINT_set_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL);
2651        break;
2652    default:
2653        jniThrowRuntimeException(env, "invalid curve type");
2654        return;
2655    }
2656
2657    if (ret != 1) {
2658        throwExceptionIfNecessary(env, "EC_POINT_set_affine_coordinates");
2659    }
2660
2661    JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => %d", group, point,
2662            xjavaBytes, yjavaBytes, ret);
2663}
2664
2665static jobjectArray NativeCrypto_EC_POINT_get_affine_coordinates(JNIEnv* env, jclass, jlong groupRef,
2666        jlong pointRef)
2667{
2668    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2669    const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef);
2670    JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point);
2671
2672    Unique_BIGNUM x(BN_new());
2673    Unique_BIGNUM y(BN_new());
2674
2675    int ret;
2676    switch (get_EC_GROUP_type(group)) {
2677    case EC_CURVE_GFP:
2678        ret = EC_POINT_get_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL);
2679        break;
2680    case EC_CURVE_GF2M:
2681        ret = EC_POINT_get_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL);
2682        break;
2683    default:
2684        jniThrowRuntimeException(env, "invalid curve type");
2685        return NULL;
2686    }
2687    if (ret != 1) {
2688        JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point);
2689        throwExceptionIfNecessary(env, "EC_POINT_get_affine_coordinates");
2690        return NULL;
2691    }
2692
2693    jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL);
2694    if (joa == NULL) {
2695        return NULL;
2696    }
2697
2698    jbyteArray xBytes = bignumToArray(env, x.get(), "x");
2699    if (env->ExceptionCheck()) {
2700        return NULL;
2701    }
2702    env->SetObjectArrayElement(joa, 0, xBytes);
2703
2704    jbyteArray yBytes = bignumToArray(env, y.get(), "y");
2705    if (env->ExceptionCheck()) {
2706        return NULL;
2707    }
2708    env->SetObjectArrayElement(joa, 1, yBytes);
2709
2710    JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p) => %p", group, point, joa);
2711    return joa;
2712}
2713
2714static jlong NativeCrypto_EC_KEY_generate_key(JNIEnv* env, jclass, jlong groupRef)
2715{
2716    const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
2717    JNI_TRACE("EC_KEY_generate_key(%p)", group);
2718
2719    Unique_EC_KEY eckey(EC_KEY_new());
2720    if (eckey.get() == NULL) {
2721        JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_new() oom", group);
2722        jniThrowOutOfMemory(env, "Unable to create an EC_KEY");
2723        return 0;
2724    }
2725
2726    if (EC_KEY_set_group(eckey.get(), group) != 1) {
2727        JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_set_group error", group);
2728        throwExceptionIfNecessary(env, "EC_KEY_set_group");
2729        return 0;
2730    }
2731
2732    if (EC_KEY_generate_key(eckey.get()) != 1) {
2733        JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_generate_key error", group);
2734        throwExceptionIfNecessary(env, "EC_KEY_set_group");
2735        return 0;
2736    }
2737
2738    Unique_EVP_PKEY pkey(EVP_PKEY_new());
2739    if (pkey.get() == NULL) {
2740        JNI_TRACE("EC_KEY_generate_key(%p) => threw error", group);
2741        throwExceptionIfNecessary(env, "EC_KEY_generate_key");
2742        return 0;
2743    }
2744    if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
2745        jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
2746        return 0;
2747    }
2748    OWNERSHIP_TRANSFERRED(eckey);
2749
2750    JNI_TRACE("EC_KEY_generate_key(%p) => %p", group, pkey.get());
2751    return reinterpret_cast<uintptr_t>(pkey.release());
2752}
2753
2754static jlong NativeCrypto_EC_KEY_get0_group(JNIEnv* env, jclass, jlong pkeyRef)
2755{
2756    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
2757    JNI_TRACE("EC_KEY_get0_group(%p)", pkey);
2758
2759    if (pkey == NULL) {
2760        jniThrowNullPointerException(env, "pkey == null");
2761        JNI_TRACE("EC_KEY_get0_group(%p) => pkey == null", pkey);
2762        return 0;
2763    }
2764
2765    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
2766        jniThrowRuntimeException(env, "not EC key");
2767        JNI_TRACE("EC_KEY_get0_group(%p) => not EC key (type == %d)", pkey,
2768                EVP_PKEY_type(pkey->type));
2769        return 0;
2770    }
2771
2772    const EC_GROUP* group = EC_KEY_get0_group(pkey->pkey.ec);
2773    JNI_TRACE("EC_KEY_get0_group(%p) => %p", pkey, group);
2774    return reinterpret_cast<uintptr_t>(group);
2775}
2776
2777static jbyteArray NativeCrypto_EC_KEY_get_private_key(JNIEnv* env, jclass, jlong pkeyRef)
2778{
2779    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
2780    JNI_TRACE("EC_KEY_get_private_key(%p)", pkey);
2781
2782    Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
2783    if (eckey.get() == NULL) {
2784        throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY");
2785        return NULL;
2786    }
2787
2788    const BIGNUM *privkey = EC_KEY_get0_private_key(eckey.get());
2789
2790    jbyteArray privBytes = bignumToArray(env, privkey, "privkey");
2791    if (env->ExceptionCheck()) {
2792        JNI_TRACE("EC_KEY_get_private_key(%p) => threw error", pkey);
2793        return NULL;
2794    }
2795
2796    JNI_TRACE("EC_KEY_get_private_key(%p) => %p", pkey, privBytes);
2797    return privBytes;
2798}
2799
2800static jlong NativeCrypto_EC_KEY_get_public_key(JNIEnv* env, jclass, jlong pkeyRef)
2801{
2802    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
2803    JNI_TRACE("EC_KEY_get_public_key(%p)", pkey);
2804
2805    Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
2806    if (eckey.get() == NULL) {
2807        throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY");
2808        return 0;
2809    }
2810
2811    Unique_EC_POINT dup(EC_POINT_dup(EC_KEY_get0_public_key(eckey.get()),
2812            EC_KEY_get0_group(eckey.get())));
2813    if (dup.get() == NULL) {
2814        JNI_TRACE("EC_KEY_get_public_key(%p) => can't dup public key", pkey);
2815        jniThrowRuntimeException(env, "EC_POINT_dup");
2816        return 0;
2817    }
2818
2819    JNI_TRACE("EC_KEY_get_public_key(%p) => %p", pkey, dup.get());
2820    return reinterpret_cast<uintptr_t>(dup.release());
2821}
2822
2823static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass,
2824     jbyteArray outArray, jint outOffset, jlong pubkeyRef, jlong privkeyRef)
2825{
2826    EVP_PKEY* pubPkey = reinterpret_cast<EVP_PKEY*>(pubkeyRef);
2827    EVP_PKEY* privPkey = reinterpret_cast<EVP_PKEY*>(privkeyRef);
2828    JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p)", outArray, outOffset, pubPkey, privPkey);
2829
2830    ScopedByteArrayRW out(env, outArray);
2831    if (out.get() == NULL) {
2832        JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p) can't get output buffer",
2833                outArray, outOffset, pubPkey, privPkey);
2834        return -1;
2835    }
2836
2837    if ((outOffset < 0) || ((size_t) outOffset >= out.size())) {
2838        jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
2839        return -1;
2840    }
2841
2842    Unique_EC_KEY pubkey(EVP_PKEY_get1_EC_KEY(pubPkey));
2843    if (pubkey.get() == NULL) {
2844        JNI_TRACE("ECDH_compute_key(%p) => can't get public key", pubPkey);
2845        throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public");
2846        return -1;
2847    }
2848
2849    const EC_POINT* pubkeyPoint = EC_KEY_get0_public_key(pubkey.get());
2850    if (pubkeyPoint == NULL) {
2851        JNI_TRACE("ECDH_compute_key(%p) => can't get public key point", pubPkey);
2852        throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public");
2853        return -1;
2854    }
2855
2856    Unique_EC_KEY privkey(EVP_PKEY_get1_EC_KEY(privPkey));
2857    if (privkey.get() == NULL) {
2858        throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY private");
2859        return -1;
2860    }
2861
2862    int outputLength = ECDH_compute_key(
2863            &out[outOffset],
2864            out.size() - outOffset,
2865            pubkeyPoint,
2866            privkey.get(),
2867            NULL // No KDF
2868            );
2869    if (outputLength == -1) {
2870        throwExceptionIfNecessary(env, "ECDH_compute_key");
2871        return -1;
2872    }
2873
2874    return outputLength;
2875}
2876
2877static jlong NativeCrypto_EVP_MD_CTX_create(JNIEnv* env, jclass) {
2878    JNI_TRACE("EVP_MD_CTX_create()");
2879
2880    Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
2881    if (ctx.get() == NULL) {
2882        jniThrowOutOfMemory(env, "Unable create a EVP_MD_CTX");
2883        return 0;
2884    }
2885
2886    JNI_TRACE("EVP_MD_CTX_create() => %p", ctx.get());
2887    return reinterpret_cast<uintptr_t>(ctx.release());
2888}
2889
2890static void NativeCrypto_EVP_MD_CTX_init(JNIEnv*, jclass, jlong ctxRef) {
2891    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
2892    JNI_TRACE("NativeCrypto_EVP_MD_CTX_init(%p)", ctx);
2893
2894    if (ctx != NULL) {
2895        EVP_MD_CTX_init(ctx);
2896    }
2897}
2898
2899static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, jlong ctxRef) {
2900    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
2901    JNI_TRACE("NativeCrypto_EVP_MD_CTX_destroy(%p)", ctx);
2902
2903    if (ctx != NULL) {
2904        EVP_MD_CTX_destroy(ctx);
2905    }
2906}
2907
2908static jlong NativeCrypto_EVP_MD_CTX_copy(JNIEnv* env, jclass, jlong ctxRef) {
2909    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
2910    JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p)", ctx);
2911
2912    if (ctx == NULL) {
2913        jniThrowNullPointerException(env, "ctx == null");
2914        return 0;
2915    }
2916
2917    EVP_MD_CTX* copy = EVP_MD_CTX_create();
2918    if (copy == NULL) {
2919        jniThrowOutOfMemory(env, "Unable to allocate copy of EVP_MD_CTX");
2920        return 0;
2921    }
2922
2923    EVP_MD_CTX_init(copy);
2924    int result = EVP_MD_CTX_copy_ex(copy, ctx);
2925    if (result == 0) {
2926        EVP_MD_CTX_destroy(copy);
2927        jniThrowRuntimeException(env, "Unable to copy EVP_MD_CTX");
2928        freeOpenSslErrorState();
2929        return 0;
2930    }
2931
2932    JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p) => %p", ctx, copy);
2933    return reinterpret_cast<uintptr_t>(copy);
2934}
2935
2936/*
2937 * public static native int EVP_DigestFinal(int, byte[], int)
2938 */
2939static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, jlong ctxRef,
2940                                         jbyteArray hash, jint offset) {
2941    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
2942    JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset);
2943
2944    if (ctx == NULL || hash == NULL) {
2945        jniThrowNullPointerException(env, "ctx == null || hash == null");
2946        return -1;
2947    }
2948
2949    ScopedByteArrayRW hashBytes(env, hash);
2950    if (hashBytes.get() == NULL) {
2951        return -1;
2952    }
2953    unsigned int bytesWritten = -1;
2954    int ok = EVP_DigestFinal(ctx,
2955                             reinterpret_cast<unsigned char*>(hashBytes.get() + offset),
2956                             &bytesWritten);
2957    if (ok == 0) {
2958        throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestFinal");
2959    }
2960    EVP_MD_CTX_destroy(ctx);
2961
2962    JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d) => %d", ctx, hash, offset, bytesWritten);
2963    return bytesWritten;
2964}
2965
2966/*
2967 * public static native int EVP_DigestInit(int)
2968 */
2969static jlong NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, jlong evpMdRef) {
2970    EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
2971    JNI_TRACE("NativeCrypto_EVP_DigestInit(%p)", evp_md);
2972
2973    if (evp_md == NULL) {
2974        jniThrowNullPointerException(env, NULL);
2975        return 0;
2976    }
2977
2978    Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
2979    if (ctx.get() == NULL) {
2980        jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
2981        return 0;
2982    }
2983    JNI_TRACE("NativeCrypto_EVP_DigestInit ctx=%p", ctx.get());
2984
2985    int ok = EVP_DigestInit(ctx.get(), evp_md);
2986    if (ok == 0) {
2987        bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestInit");
2988        if (exception) {
2989            return 0;
2990        }
2991    }
2992    return reinterpret_cast<uintptr_t>(ctx.release());
2993}
2994
2995/*
2996 * public static native int EVP_get_digestbyname(java.lang.String)
2997 */
2998static jlong NativeCrypto_EVP_get_digestbyname(JNIEnv* env, jclass, jstring algorithm) {
2999    JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%p)", algorithm);
3000
3001    if (algorithm == NULL) {
3002        jniThrowNullPointerException(env, NULL);
3003        return -1;
3004    }
3005
3006    ScopedUtfChars algorithmChars(env, algorithm);
3007    if (algorithmChars.c_str() == NULL) {
3008        return 0;
3009    }
3010    JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s)", algorithmChars.c_str());
3011
3012    const EVP_MD* evp_md = EVP_get_digestbyname(algorithmChars.c_str());
3013    if (evp_md == NULL) {
3014        jniThrowRuntimeException(env, "Hash algorithm not found");
3015        return 0;
3016    }
3017
3018    JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => %p", algorithmChars.c_str(), evp_md);
3019    return reinterpret_cast<uintptr_t>(evp_md);
3020}
3021
3022/*
3023 * public static native int EVP_MD_size(int)
3024 */
3025static jint NativeCrypto_EVP_MD_size(JNIEnv* env, jclass, jint evpMdRef) {
3026    EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
3027    JNI_TRACE("NativeCrypto_EVP_MD_size(%p)", evp_md);
3028
3029    if (evp_md == NULL) {
3030        jniThrowNullPointerException(env, NULL);
3031        return -1;
3032    }
3033
3034    int result = EVP_MD_size(evp_md);
3035    JNI_TRACE("NativeCrypto_EVP_MD_size(%p) => %d", evp_md, result);
3036    return result;
3037}
3038
3039/*
3040 * public static int void EVP_MD_block_size(int)
3041 */
3042static jint NativeCrypto_EVP_MD_block_size(JNIEnv* env, jclass, jlong evpMdRef) {
3043    EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
3044    JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p)", evp_md);
3045
3046    if (evp_md == NULL) {
3047        jniThrowNullPointerException(env, NULL);
3048        return -1;
3049    }
3050
3051    int result = EVP_MD_block_size(evp_md);
3052    JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p) => %d", evp_md, result);
3053    return result;
3054}
3055
3056/*
3057 * public static native void EVP_DigestUpdate(int, byte[], int, int)
3058 */
3059static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, jlong ctxRef,
3060                                          jbyteArray buffer, jint offset, jint length) {
3061    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
3062    JNI_TRACE("NativeCrypto_EVP_DigestUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
3063
3064    if (offset < 0 || length < 0) {
3065        jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
3066        return;
3067    }
3068
3069    if (ctx == NULL || buffer == NULL) {
3070        jniThrowNullPointerException(env, NULL);
3071        return;
3072    }
3073
3074    ScopedByteArrayRO bufferBytes(env, buffer);
3075    if (bufferBytes.get() == NULL) {
3076        return;
3077    }
3078    int ok = EVP_DigestUpdate(ctx,
3079                              reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
3080                              length);
3081    if (ok == 0) {
3082        throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestUpdate");
3083    }
3084}
3085
3086static void NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jlong evpMdCtxRef,
3087        const jlong evpMdRef, jlong pkeyRef) {
3088    EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
3089    const EVP_MD* md = reinterpret_cast<const EVP_MD*>(evpMdRef);
3090    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
3091    JNI_TRACE("EVP_DigestSignInit(%p, %p, %p)", mdCtx, md, pkey);
3092
3093    if (mdCtx == NULL) {
3094         jniThrowNullPointerException(env, "mdCtx == null");
3095         return;
3096    }
3097
3098    if (md == NULL) {
3099         jniThrowNullPointerException(env, "md == null");
3100         return;
3101    }
3102
3103    if (pkey == NULL) {
3104         jniThrowNullPointerException(env, "pkey == null");
3105         return;
3106    }
3107
3108    if (EVP_DigestSignInit(mdCtx, (EVP_PKEY_CTX **) NULL, md, (ENGINE *) NULL, pkey) <= 0) {
3109        JNI_TRACE("ctx=%p EVP_DigestSignInit => threw exception", mdCtx);
3110        throwExceptionIfNecessary(env, "EVP_DigestSignInit");
3111        return;
3112    }
3113
3114    JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) => success", mdCtx, md, pkey);
3115}
3116
3117static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jint evpMdCtxRef,
3118        jbyteArray inJavaBytes, jint inOffset, jint inLength)
3119{
3120    EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
3121    JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d)", mdCtx, inJavaBytes, inOffset, inLength);
3122
3123    if (mdCtx == NULL) {
3124         jniThrowNullPointerException(env, "mdCtx == null");
3125         return;
3126    }
3127
3128    ScopedByteArrayRO inBytes(env, inJavaBytes);
3129    if (inBytes.get() == NULL) {
3130        return;
3131    }
3132
3133    if (inOffset < 0 || size_t(inOffset) > inBytes.size()) {
3134        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inOffset");
3135        return;
3136    }
3137
3138    const ssize_t inEnd = inOffset + inLength;
3139    if (inEnd < 0 || size_t(inEnd) >= inBytes.size()) {
3140        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inLength");
3141        return;
3142    }
3143
3144    const unsigned char *tmp = reinterpret_cast<const unsigned char *>(inBytes.get());
3145    if (!EVP_DigestSignUpdate(mdCtx, tmp + inOffset, inLength)) {
3146        JNI_TRACE("ctx=%p EVP_DigestSignUpdate => threw exception", mdCtx);
3147        throwExceptionIfNecessary(env, "EVP_DigestSignUpdate");
3148    }
3149
3150    JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d) => success", mdCtx, inJavaBytes, inOffset,
3151            inLength);
3152}
3153
3154static jbyteArray NativeCrypto_EVP_DigestSignFinal(JNIEnv* env, jclass, jlong evpMdCtxRef)
3155{
3156    EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
3157    JNI_TRACE("EVP_DigestSignFinal(%p)", mdCtx);
3158
3159    if (mdCtx == NULL) {
3160         jniThrowNullPointerException(env, "mdCtx == null");
3161         return NULL;
3162    }
3163
3164    const size_t expectedSize = EVP_MD_CTX_size(mdCtx);
3165    ScopedLocalRef<jbyteArray> outJavaBytes(env, env->NewByteArray(expectedSize));
3166    if (outJavaBytes.get() == NULL) {
3167        return NULL;
3168    }
3169    ScopedByteArrayRW outBytes(env, outJavaBytes.get());
3170    if (outBytes.get() == NULL) {
3171        return NULL;
3172    }
3173    unsigned char *tmp = reinterpret_cast<unsigned char*>(outBytes.get());
3174    size_t len;
3175    if (!EVP_DigestSignFinal(mdCtx, tmp, &len)) {
3176        JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx);
3177        throwExceptionIfNecessary(env, "EVP_DigestSignFinal");
3178        return 0;
3179    }
3180
3181    if (len != expectedSize) {
3182        jniThrowRuntimeException(env, "hash size unexpected");
3183        return 0;
3184    }
3185
3186    JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, outJavaBytes.get());
3187    return outJavaBytes.release();
3188}
3189
3190static jlong NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jstring algorithm) {
3191    JNI_TRACE("NativeCrypto_EVP_SignInit(%p)", algorithm);
3192
3193    if (algorithm == NULL) {
3194        jniThrowNullPointerException(env, NULL);
3195        return 0;
3196    }
3197
3198    Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
3199    if (ctx.get() == NULL) {
3200        jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
3201        return 0;
3202    }
3203    JNI_TRACE("NativeCrypto_EVP_SignInit ctx=%p", ctx.get());
3204
3205    ScopedUtfChars algorithmChars(env, algorithm);
3206    if (algorithmChars.c_str() == NULL) {
3207        return 0;
3208    }
3209    JNI_TRACE("NativeCrypto_EVP_SignInit algorithmChars=%s", algorithmChars.c_str());
3210
3211    const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
3212    if (digest == NULL) {
3213        JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => hash not found", algorithmChars.c_str());
3214        throwExceptionIfNecessary(env, "Hash algorithm not found");
3215        return 0;
3216    }
3217
3218    int ok = EVP_SignInit(ctx.get(), digest);
3219    if (ok == 0) {
3220        bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignInit");
3221        if (exception) {
3222            JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => threw exception", algorithmChars.c_str());
3223            return 0;
3224        }
3225    }
3226
3227    JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => %p", algorithmChars.c_str(), ctx.get());
3228    return reinterpret_cast<uintptr_t>(ctx.release());
3229}
3230
3231/*
3232 * public static native void EVP_SignUpdate(int, byte[], int, int)
3233 */
3234static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jlong ctxRef,
3235                                          jbyteArray buffer, jint offset, jint length) {
3236    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
3237    JNI_TRACE("NativeCrypto_EVP_SignUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
3238
3239    if (ctx == NULL || buffer == NULL) {
3240        jniThrowNullPointerException(env, NULL);
3241        return;
3242    }
3243
3244    ScopedByteArrayRO bufferBytes(env, buffer);
3245    if (bufferBytes.get() == NULL) {
3246        return;
3247    }
3248    int ok = EVP_SignUpdate(ctx,
3249                            reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
3250                            length);
3251    if (ok == 0) {
3252        throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignUpdate");
3253    }
3254}
3255
3256/*
3257 * public static native int EVP_SignFinal(int, byte[], int, int)
3258 */
3259static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray signature,
3260        jint offset, jlong pkeyRef) {
3261    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
3262    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
3263    JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctx, signature, offset, pkey);
3264
3265    if (ctx == NULL || pkey == NULL) {
3266        jniThrowNullPointerException(env, NULL);
3267        return -1;
3268    }
3269
3270    ScopedByteArrayRW signatureBytes(env, signature);
3271    if (signatureBytes.get() == NULL) {
3272        return -1;
3273    }
3274    unsigned int bytesWritten = -1;
3275    int ok = EVP_SignFinal(ctx,
3276                           reinterpret_cast<unsigned char*>(signatureBytes.get() + offset),
3277                           &bytesWritten,
3278                           pkey);
3279    if (ok == 0) {
3280        throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal");
3281    }
3282    JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u",
3283              ctx, signature, offset, pkey, bytesWritten);
3284
3285    return bytesWritten;
3286}
3287
3288/*
3289 * public static native int EVP_VerifyInit(java.lang.String)
3290 */
3291static jlong NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jstring algorithm) {
3292    JNI_TRACE("NativeCrypto_EVP_VerifyInit(%p)", algorithm);
3293
3294    if (algorithm == NULL) {
3295        jniThrowNullPointerException(env, NULL);
3296        return 0;
3297    }
3298
3299    Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
3300    if (ctx.get() == NULL) {
3301        jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
3302        return 0;
3303    }
3304    JNI_TRACE("NativeCrypto_EVP_VerifyInit ctx=%p", ctx.get());
3305
3306    ScopedUtfChars algorithmChars(env, algorithm);
3307    if (algorithmChars.c_str() == NULL) {
3308        return 0;
3309    }
3310    JNI_TRACE("NativeCrypto_EVP_VerifyInit algorithmChars=%s", algorithmChars.c_str());
3311
3312    const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
3313    if (digest == NULL) {
3314        jniThrowRuntimeException(env, "Hash algorithm not found");
3315        return 0;
3316    }
3317
3318    int ok = EVP_VerifyInit(ctx.get(), digest);
3319    if (ok == 0) {
3320        bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyInit");
3321        if (exception) {
3322            return 0;
3323        }
3324    }
3325    return reinterpret_cast<uintptr_t>(ctx.release());
3326}
3327
3328/*
3329 * public static native void EVP_VerifyUpdate(int, byte[], int, int)
3330 */
3331static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jlong ctxRef,
3332                                          jbyteArray buffer, jint offset, jint length) {
3333    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
3334    JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
3335
3336    if (ctx == NULL || buffer == NULL) {
3337        jniThrowNullPointerException(env, NULL);
3338        return;
3339    }
3340
3341    ScopedByteArrayRO bufferBytes(env, buffer);
3342    if (bufferBytes.get() == NULL) {
3343        return;
3344    }
3345    int ok = EVP_VerifyUpdate(ctx,
3346                              reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
3347                              length);
3348    if (ok == 0) {
3349        throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate");
3350    }
3351}
3352
3353/*
3354 * public static native int EVP_VerifyFinal(int, byte[], int, int, int)
3355 */
3356static jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray buffer,
3357                                        jint offset, jint length, jlong pkeyRef) {
3358    EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
3359    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
3360    JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)",
3361              ctx, buffer, offset, length, pkey);
3362
3363    if (ctx == NULL || buffer == NULL || pkey == NULL) {
3364        jniThrowNullPointerException(env, NULL);
3365        return -1;
3366    }
3367
3368    ScopedByteArrayRO bufferBytes(env, buffer);
3369    if (bufferBytes.get() == NULL) {
3370        return -1;
3371    }
3372    int ok = EVP_VerifyFinal(ctx,
3373                             reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
3374                             length,
3375                             pkey);
3376    if (ok < 0) {
3377        throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal");
3378    }
3379
3380    /*
3381     * For DSA keys, OpenSSL appears to have a bug where it returns
3382     * errors for any result != 1. See dsa_ossl.c in dsa_do_verify
3383     */
3384    freeOpenSslErrorState();
3385
3386    JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
3387              ctx, buffer, offset, length, pkey, ok);
3388
3389    return ok;
3390}
3391
3392static jlong NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) {
3393    JNI_TRACE("EVP_get_cipherbyname(%p)", algorithm);
3394    if (algorithm == NULL) {
3395        JNI_TRACE("EVP_get_cipherbyname(%p) => threw exception algorithm == null", algorithm);
3396        jniThrowNullPointerException(env, NULL);
3397        return -1;
3398    }
3399
3400    ScopedUtfChars algorithmChars(env, algorithm);
3401    if (algorithmChars.c_str() == NULL) {
3402        return 0;
3403    }
3404    JNI_TRACE("EVP_get_cipherbyname(%p) => algorithm = %s", algorithm, algorithmChars.c_str());
3405
3406    const EVP_CIPHER* evp_cipher = EVP_get_cipherbyname(algorithmChars.c_str());
3407    if (evp_cipher == NULL) {
3408        freeOpenSslErrorState();
3409    }
3410
3411    JNI_TRACE("EVP_get_cipherbyname(%s) => %p", algorithmChars.c_str(), evp_cipher);
3412    return reinterpret_cast<uintptr_t>(evp_cipher);
3413}
3414
3415static void NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jlong ctxRef, jlong evpCipherRef,
3416        jbyteArray keyArray, jbyteArray ivArray, jboolean encrypting) {
3417    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3418    const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef);
3419    JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d)", ctx, evpCipher, keyArray, ivArray,
3420            encrypting ? 1 : 0);
3421
3422    if (ctx == NULL) {
3423        jniThrowNullPointerException(env, "ctx == null");
3424        JNI_TRACE("EVP_CipherUpdate => ctx == null");
3425        return;
3426    }
3427
3428    // The key can be null if we need to set extra parameters.
3429    UniquePtr<unsigned char[]> keyPtr;
3430    if (keyArray != NULL) {
3431        ScopedByteArrayRO keyBytes(env, keyArray);
3432        if (keyBytes.get() == NULL) {
3433            return;
3434        }
3435
3436        keyPtr.reset(new unsigned char[keyBytes.size()]);
3437        memcpy(keyPtr.get(), keyBytes.get(), keyBytes.size());
3438    }
3439
3440    // The IV can be null if we're using ECB.
3441    UniquePtr<unsigned char[]> ivPtr;
3442    if (ivArray != NULL) {
3443        ScopedByteArrayRO ivBytes(env, ivArray);
3444        if (ivBytes.get() == NULL) {
3445            return;
3446        }
3447
3448        ivPtr.reset(new unsigned char[ivBytes.size()]);
3449        memcpy(ivPtr.get(), ivBytes.get(), ivBytes.size());
3450    }
3451
3452    if (!EVP_CipherInit_ex(ctx, evpCipher, NULL, keyPtr.get(), ivPtr.get(), encrypting ? 1 : 0)) {
3453        throwExceptionIfNecessary(env, "EVP_CipherInit_ex");
3454        JNI_TRACE("EVP_CipherInit_ex => error initializing cipher");
3455        return;
3456    }
3457
3458    JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d) => success", ctx, evpCipher, keyArray, ivArray,
3459            encrypting ? 1 : 0);
3460}
3461
3462/*
3463 *  public static native int EVP_CipherUpdate(int ctx, byte[] out, int outOffset, byte[] in,
3464 *          int inOffset);
3465 */
3466static jint NativeCrypto_EVP_CipherUpdate(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray,
3467        jint outOffset, jbyteArray inArray, jint inOffset, jint inLength) {
3468    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3469    JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d)", ctx, outArray, outOffset, inArray, inOffset);
3470
3471    if (ctx == NULL) {
3472        jniThrowNullPointerException(env, "ctx == null");
3473        JNI_TRACE("ctx=%p EVP_CipherUpdate => ctx == null", ctx);
3474        return 0;
3475    }
3476
3477    ScopedByteArrayRO inBytes(env, inArray);
3478    if (inBytes.get() == NULL) {
3479        return 0;
3480    }
3481    const size_t inSize = inBytes.size();
3482    if (size_t(inOffset + inLength) > inSize) {
3483        jniThrowException(env, "java/lang/IndexOutOfBoundsException",
3484                "in.length < (inSize + inOffset)");
3485        return 0;
3486    }
3487
3488    ScopedByteArrayRW outBytes(env, outArray);
3489    if (outBytes.get() == NULL) {
3490        return 0;
3491    }
3492    const size_t outSize = outBytes.size();
3493    if (size_t(outOffset + inLength) > outSize) {
3494        jniThrowException(env, "java/lang/IndexOutOfBoundsException",
3495                "out.length < inSize + outOffset + blockSize - 1");
3496        return 0;
3497    }
3498
3499    JNI_TRACE("ctx=%p EVP_CipherUpdate in=%p in.length=%d inOffset=%d inLength=%d out=%p out.length=%d outOffset=%d",
3500            ctx, inBytes.get(), inBytes.size(), inOffset, inLength, outBytes.get(), outBytes.size(), outOffset);
3501
3502    unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
3503    const unsigned char* in = reinterpret_cast<const unsigned char*>(inBytes.get());
3504
3505    int outl;
3506    if (!EVP_CipherUpdate(ctx, out + outOffset, &outl, in + inOffset, inLength)) {
3507        throwExceptionIfNecessary(env, "EVP_CipherUpdate");
3508        JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx);
3509        return 0;
3510    }
3511
3512    JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d) => %d", ctx, outArray, outOffset, inArray,
3513            inOffset, outl);
3514    return outl;
3515}
3516
3517static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray,
3518        jint outOffset) {
3519    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3520    JNI_TRACE("EVP_CipherFinal_ex(%p, %p, %d)", ctx, outArray, outOffset);
3521
3522    if (ctx == NULL) {
3523        jniThrowNullPointerException(env, "ctx == null");
3524        JNI_TRACE("ctx=%p EVP_CipherFinal_ex => ctx == null", ctx);
3525        return 0;
3526    }
3527
3528    ScopedByteArrayRW outBytes(env, outArray);
3529    if (outBytes.get() == NULL) {
3530        return 0;
3531    }
3532
3533    unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
3534
3535    int outl;
3536    if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) {
3537        throwExceptionIfNecessary(env, "EVP_CipherFinal_ex");
3538        JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw error", ctx);
3539        return 0;
3540    }
3541
3542    JNI_TRACE("EVP_CipherFinal(%p, %p, %d) => %d", ctx, outArray, outOffset, outl);
3543    return outl;
3544}
3545
3546static jint NativeCrypto_EVP_CIPHER_iv_length(JNIEnv* env, jclass, jlong evpCipherRef) {
3547    const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef);
3548    JNI_TRACE("EVP_CIPHER_iv_length(%p)", evpCipher);
3549
3550    if (evpCipher == NULL) {
3551        jniThrowNullPointerException(env, "evpCipher == null");
3552        JNI_TRACE("EVP_CIPHER_iv_length => evpCipher == null");
3553        return 0;
3554    }
3555
3556    const int ivLength = EVP_CIPHER_iv_length(evpCipher);
3557    JNI_TRACE("EVP_CIPHER_iv_length(%p) => %d", evpCipher, ivLength);
3558    return ivLength;
3559}
3560
3561static jlong NativeCrypto_EVP_CIPHER_CTX_new(JNIEnv* env, jclass) {
3562    JNI_TRACE("EVP_CIPHER_CTX_new()");
3563
3564    Unique_EVP_CIPHER_CTX ctx(EVP_CIPHER_CTX_new());
3565    if (ctx.get() == NULL) {
3566        jniThrowOutOfMemory(env, "Unable to allocate cipher context");
3567        JNI_TRACE("EVP_CipherInit_ex => context allocation error");
3568        return 0;
3569    }
3570
3571    JNI_TRACE("EVP_CIPHER_CTX_new() => %p", ctx.get());
3572    return reinterpret_cast<uintptr_t>(ctx.release());
3573}
3574
3575static jint NativeCrypto_EVP_CIPHER_CTX_block_size(JNIEnv* env, jclass, jlong ctxRef) {
3576    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3577    JNI_TRACE("EVP_CIPHER_CTX_block_size(%p)", ctx);
3578
3579    if (ctx == NULL) {
3580        jniThrowNullPointerException(env, "ctx == null");
3581        JNI_TRACE("ctx=%p EVP_CIPHER_CTX_block_size => ctx == null", ctx);
3582        return 0;
3583    }
3584
3585    int blockSize = EVP_CIPHER_CTX_block_size(ctx);
3586    JNI_TRACE("EVP_CIPHER_CTX_block_size(%p) => %d", ctx, blockSize);
3587    return blockSize;
3588}
3589
3590static jint NativeCrypto_get_EVP_CIPHER_CTX_buf_len(JNIEnv* env, jclass, jlong ctxRef) {
3591    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3592    JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p)", ctx);
3593
3594    if (ctx == NULL) {
3595        jniThrowNullPointerException(env, "ctx == null");
3596        JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_buf_len => ctx == null", ctx);
3597        return 0;
3598    }
3599
3600    int buf_len = ctx->buf_len;
3601    JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p) => %d", ctx, buf_len);
3602    return buf_len;
3603}
3604
3605static void NativeCrypto_EVP_CIPHER_CTX_set_padding(JNIEnv* env, jclass, jlong ctxRef, jboolean enablePaddingBool) {
3606    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3607    jint enablePadding = enablePaddingBool ? 1 : 0;
3608    JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d)", ctx, enablePadding);
3609
3610    if (ctx == NULL) {
3611        jniThrowNullPointerException(env, "ctx == null");
3612        JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_padding => ctx == null", ctx);
3613        return;
3614    }
3615
3616    EVP_CIPHER_CTX_set_padding(ctx, enablePadding); // Not void, but always returns 1.
3617    JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d) => success", ctx, enablePadding);
3618}
3619
3620static void NativeCrypto_EVP_CIPHER_CTX_set_key_length(JNIEnv* env, jclass, jlong ctxRef,
3621        jint keySizeBits) {
3622    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3623    JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d)", ctx, keySizeBits);
3624
3625    if (ctx == NULL) {
3626        jniThrowNullPointerException(env, "ctx == null");
3627        JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_key_length => ctx == null", ctx);
3628        return;
3629    }
3630
3631    if (!EVP_CIPHER_CTX_set_key_length(ctx, keySizeBits)) {
3632        throwExceptionIfNecessary(env, "NativeCrypto_EVP_CIPHER_CTX_set_key_length");
3633        JNI_TRACE("NativeCrypto_EVP_CIPHER_CTX_set_key_length => threw error");
3634        return;
3635    }
3636    JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d) => success", ctx, keySizeBits);
3637}
3638
3639static void NativeCrypto_EVP_CIPHER_CTX_cleanup(JNIEnv* env, jclass, jlong ctxRef) {
3640    EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
3641    JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p)", ctx);
3642
3643    if (ctx != NULL) {
3644        if (!EVP_CIPHER_CTX_cleanup(ctx)) {
3645            throwExceptionIfNecessary(env, "EVP_CIPHER_CTX_cleanup");
3646            JNI_TRACE("EVP_CIPHER_CTX_cleanup => threw error");
3647            return;
3648        }
3649    }
3650    JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p) => success", ctx);
3651}
3652
3653/**
3654 * public static native void RAND_seed(byte[]);
3655 */
3656static void NativeCrypto_RAND_seed(JNIEnv* env, jclass, jbyteArray seed) {
3657    JNI_TRACE("NativeCrypto_RAND_seed seed=%p", seed);
3658    ScopedByteArrayRO randseed(env, seed);
3659    if (randseed.get() == NULL) {
3660        return;
3661    }
3662    RAND_seed(randseed.get(), randseed.size());
3663}
3664
3665static jint NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) {
3666    JNI_TRACE("NativeCrypto_RAND_load_file filename=%p max_bytes=%lld", filename, max_bytes);
3667    ScopedUtfChars file(env, filename);
3668    if (file.c_str() == NULL) {
3669        return -1;
3670    }
3671    int result = RAND_load_file(file.c_str(), max_bytes);
3672    JNI_TRACE("NativeCrypto_RAND_load_file file=%s => %d", file.c_str(), result);
3673    return result;
3674}
3675
3676static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) {
3677    JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output);
3678
3679    ScopedByteArrayRW outputBytes(env, output);
3680    if (outputBytes.get() == NULL) {
3681        return;
3682    }
3683
3684    unsigned char* tmp = reinterpret_cast<unsigned char*>(outputBytes.get());
3685    if (RAND_bytes(tmp, outputBytes.size()) <= 0) {
3686        throwExceptionIfNecessary(env, "NativeCrypto_RAND_bytes");
3687        JNI_TRACE("tmp=%p NativeCrypto_RAND_bytes => threw error", tmp);
3688        return;
3689    }
3690
3691    JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output);
3692}
3693
3694static jint NativeCrypto_OBJ_txt2nid(JNIEnv* env, jclass, jstring oidStr) {
3695    JNI_TRACE("OBJ_txt2nid(%p)", oidStr);
3696
3697    ScopedUtfChars oid(env, oidStr);
3698    if (oid.c_str() == NULL) {
3699        return 0;
3700    }
3701
3702    int nid = OBJ_txt2nid(oid.c_str());
3703    JNI_TRACE("OBJ_txt2nid(%s) => %d", oid.c_str(), nid);
3704    return nid;
3705}
3706
3707static jstring NativeCrypto_OBJ_txt2nid_longName(JNIEnv* env, jclass, jstring oidStr) {
3708    JNI_TRACE("OBJ_txt2nid_longName(%p)", oidStr);
3709
3710    ScopedUtfChars oid(env, oidStr);
3711    if (oid.c_str() == NULL) {
3712        return NULL;
3713    }
3714
3715    JNI_TRACE("OBJ_txt2nid_longName(%s)", oid.c_str());
3716
3717    int nid = OBJ_txt2nid(oid.c_str());
3718    if (nid == NID_undef) {
3719        JNI_TRACE("OBJ_txt2nid_longName(%s) => NID_undef", oid.c_str());
3720        freeOpenSslErrorState();
3721        return NULL;
3722    }
3723
3724    const char* longName = OBJ_nid2ln(nid);
3725    JNI_TRACE("OBJ_txt2nid_longName(%s) => %s", oid.c_str(), longName);
3726    return env->NewStringUTF(longName);
3727}
3728
3729static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, ASN1_OBJECT* obj) {
3730    /*
3731     * The OBJ_obj2txt API doesn't "measure" if you pass in NULL as the buffer.
3732     * Just make a buffer that's large enough here. The documentation recommends
3733     * 80 characters.
3734     */
3735    char output[128];
3736    int ret = OBJ_obj2txt(output, sizeof(output), obj, 1);
3737    if (ret < 0) {
3738        throwExceptionIfNecessary(env, "ASN1_OBJECT_to_OID_string");
3739        return NULL;
3740    } else if (size_t(ret) >= sizeof(output)) {
3741        jniThrowRuntimeException(env, "ASN1_OBJECT_to_OID_string buffer too small");
3742        return NULL;
3743    }
3744
3745    JNI_TRACE("ASN1_OBJECT_to_OID_string(%p) => %s", obj, output);
3746    return env->NewStringUTF(output);
3747}
3748
3749static jlong NativeCrypto_create_BIO_InputStream(JNIEnv* env, jclass, jobject streamObj) {
3750    JNI_TRACE("create_BIO_InputStream(%p)", streamObj);
3751
3752    if (streamObj == NULL) {
3753        jniThrowNullPointerException(env, "stream == null");
3754        return 0;
3755    }
3756
3757    Unique_BIO bio(BIO_new(&stream_bio_method));
3758    if (bio.get() == NULL) {
3759        return 0;
3760    }
3761
3762    bio_stream_assign(bio.get(), new BIO_InputStream(streamObj));
3763
3764    JNI_TRACE("create_BIO_InputStream(%p) => %p", streamObj, bio.get());
3765    return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release()));
3766}
3767
3768static jlong NativeCrypto_create_BIO_OutputStream(JNIEnv* env, jclass, jobject streamObj) {
3769    JNI_TRACE("create_BIO_OutputStream(%p)", streamObj);
3770
3771    if (streamObj == NULL) {
3772        jniThrowNullPointerException(env, "stream == null");
3773        return 0;
3774    }
3775
3776    Unique_BIO bio(BIO_new(&stream_bio_method));
3777    if (bio.get() == NULL) {
3778        return 0;
3779    }
3780
3781    bio_stream_assign(bio.get(), new BIO_OutputStream(streamObj));
3782
3783    JNI_TRACE("create_BIO_OutputStream(%p) => %p", streamObj, bio.get());
3784    return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release()));
3785}
3786
3787static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
3788    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
3789    JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes);
3790
3791    if (outputJavaBytes == NULL) {
3792        jniThrowNullPointerException(env, "output == null");
3793        JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes);
3794        return 0;
3795    }
3796
3797    int outputSize = env->GetArrayLength(outputJavaBytes);
3798
3799    UniquePtr<unsigned char[]> buffer(new unsigned char[outputSize]);
3800    if (buffer.get() == NULL) {
3801        jniThrowOutOfMemory(env, "Unable to allocate buffer for read");
3802        return 0;
3803    }
3804
3805    int read = BIO_read(bio, buffer.get(), outputSize);
3806    if (read <= 0) {
3807        jniThrowException(env, "java/io/IOException", "BIO_read");
3808        JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes);
3809        return 0;
3810    }
3811
3812    env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get()));
3813    JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read);
3814    return read;
3815}
3816
3817static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes,
3818        jint offset, jint length) {
3819    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
3820    JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length);
3821
3822    if (inputJavaBytes == NULL) {
3823        jniThrowNullPointerException(env, "input == null");
3824        return;
3825    }
3826
3827    if (offset < 0 || length < 0) {
3828        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "offset < 0 || length < 0");
3829        JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
3830        return;
3831    }
3832
3833    int inputSize = env->GetArrayLength(inputJavaBytes);
3834    if (inputSize < offset + length) {
3835        jniThrowException(env, "java/lang/IndexOutOfBoundsException",
3836                "input.length < offset + length");
3837        JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
3838        return;
3839    }
3840
3841    UniquePtr<unsigned char[]> buffer(new unsigned char[length]);
3842    if (buffer.get() == NULL) {
3843        jniThrowOutOfMemory(env, "Unable to allocate buffer for write");
3844        return;
3845    }
3846
3847    env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get()));
3848    if (BIO_write(bio, buffer.get(), length) != length) {
3849        freeOpenSslErrorState();
3850        jniThrowException(env, "java/io/IOException", "BIO_write");
3851        JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length);
3852        return;
3853    }
3854
3855    JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length);
3856}
3857
3858static void NativeCrypto_BIO_free(JNIEnv* env, jclass, jlong bioRef) {
3859    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
3860    JNI_TRACE("BIO_free(%p)", bio);
3861
3862    if (bio == NULL) {
3863        jniThrowNullPointerException(env, "bio == null");
3864        return;
3865    }
3866
3867    BIO_free(bio);
3868}
3869
3870static jstring X509_NAME_to_jstring(JNIEnv* env, X509_NAME* name, unsigned long flags) {
3871    JNI_TRACE("X509_NAME_to_jstring(%p)", name);
3872
3873    Unique_BIO buffer(BIO_new(BIO_s_mem()));
3874    if (buffer.get() == NULL) {
3875        jniThrowOutOfMemory(env, "Unable to allocate BIO");
3876        JNI_TRACE("X509_NAME_to_jstring(%p) => threw error", name);
3877        return NULL;
3878    }
3879
3880    /* Don't interpret the string. */
3881    flags &= ~(ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_MSB);
3882
3883    /* Write in given format and null terminate. */
3884    X509_NAME_print_ex(buffer.get(), name, 0, flags);
3885    BIO_write(buffer.get(), "\0", 1);
3886
3887    char *tmp;
3888    BIO_get_mem_data(buffer.get(), &tmp);
3889    JNI_TRACE("X509_NAME_to_jstring(%p) => \"%s\"", name, tmp);
3890    return env->NewStringUTF(tmp);
3891}
3892
3893
3894/**
3895 * Converts GENERAL_NAME items to the output format expected in
3896 * X509Certificate#getSubjectAlternativeNames and
3897 * X509Certificate#getIssuerAlternativeNames return.
3898 */
3899static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) {
3900    switch (gen->type) {
3901    case GEN_EMAIL:
3902    case GEN_DNS:
3903    case GEN_URI: {
3904        // This must not be a T61String and must not contain NULLs.
3905        const char* data = reinterpret_cast<const char*>(ASN1_STRING_data(gen->d.ia5));
3906        ssize_t len = ASN1_STRING_length(gen->d.ia5);
3907        if ((len == static_cast<ssize_t>(strlen(data)))
3908                && (ASN1_PRINTABLE_type(ASN1_STRING_data(gen->d.ia5), len) != V_ASN1_T61STRING)) {
3909            JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI \"%s\"", gen, data);
3910            return env->NewStringUTF(data);
3911        } else {
3912            jniThrowException(env, "java/security/cert/CertificateParsingException",
3913                    "Invalid dNSName encoding");
3914            JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI invalid", gen);
3915            return NULL;
3916        }
3917    }
3918    case GEN_DIRNAME:
3919        /* Write in RFC 2253 format */
3920        return X509_NAME_to_jstring(env, gen->d.directoryName, XN_FLAG_RFC2253);
3921    case GEN_IPADD: {
3922        const void *ip = reinterpret_cast<const void *>(gen->d.ip->data);
3923        if (gen->d.ip->length == 4) {
3924            // IPv4
3925            UniquePtr<char[]> buffer(new char[INET_ADDRSTRLEN]);
3926            if (inet_ntop(AF_INET, ip, buffer.get(), INET_ADDRSTRLEN) != NULL) {
3927                JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 %s", gen, buffer.get());
3928                return env->NewStringUTF(buffer.get());
3929            } else {
3930                JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 failed %s", gen, strerror(errno));
3931            }
3932        } else if (gen->d.ip->length == 16) {
3933            // IPv6
3934            UniquePtr<char[]> buffer(new char[INET6_ADDRSTRLEN]);
3935            if (inet_ntop(AF_INET6, ip, buffer.get(), INET6_ADDRSTRLEN) != NULL) {
3936                JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 %s", gen, buffer.get());
3937                return env->NewStringUTF(buffer.get());
3938            } else {
3939                JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 failed %s", gen, strerror(errno));
3940            }
3941        }
3942
3943        /* Invalid IP encodings are pruned out without throwing an exception. */
3944        return NULL;
3945    }
3946    case GEN_RID:
3947        return ASN1_OBJECT_to_OID_string(env, gen->d.registeredID);
3948    case GEN_OTHERNAME:
3949    case GEN_X400:
3950    default:
3951        return ASN1ToByteArray<GENERAL_NAME, i2d_GENERAL_NAME>(env, gen);
3952    }
3953
3954    return NULL;
3955}
3956
3957#define GN_STACK_SUBJECT_ALT_NAME 1
3958#define GN_STACK_ISSUER_ALT_NAME 2
3959
3960static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass, jlong x509Ref,
3961        jint type) {
3962    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
3963    JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d)", x509, type);
3964
3965    if (x509 == NULL) {
3966        jniThrowNullPointerException(env, "x509 == null");
3967        JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => x509 == null", x509, type);
3968        return NULL;
3969    }
3970
3971    X509_check_ca(x509);
3972
3973    STACK_OF(GENERAL_NAME)* gn_stack;
3974    Unique_sk_GENERAL_NAME stackHolder;
3975    if (type == GN_STACK_SUBJECT_ALT_NAME) {
3976        gn_stack = x509->altname;
3977    } else if (type == GN_STACK_ISSUER_ALT_NAME) {
3978        stackHolder.reset(
3979                static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(x509, NID_issuer_alt_name,
3980                        NULL, NULL)));
3981        gn_stack = stackHolder.get();
3982    } else {
3983        JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => unknown type", x509, type);
3984        return NULL;
3985    }
3986
3987    int count = sk_GENERAL_NAME_num(gn_stack);
3988    if (count <= 0) {
3989        JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no entries)", x509, type);
3990        return NULL;
3991    }
3992
3993    /*
3994     * Keep track of how many originally so we can ignore any invalid
3995     * values later.
3996     */
3997    const int origCount = count;
3998
3999    ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, objectArrayClass, NULL));
4000    for (int i = 0, j = 0; i < origCount; i++, j++) {
4001        GENERAL_NAME* gen = sk_GENERAL_NAME_value(gn_stack, i);
4002        ScopedLocalRef<jobject> val(env, GENERAL_NAME_to_jobject(env, gen));
4003        if (env->ExceptionCheck()) {
4004            JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => threw exception parsing gen name",
4005                    x509, type);
4006            return NULL;
4007        }
4008
4009        /*
4010         * If it's NULL, we'll have to skip this, reduce the number of total
4011         * entries, and fix up the array later.
4012         */
4013        if (val.get() == NULL) {
4014            j--;
4015            count--;
4016            continue;
4017        }
4018
4019        ScopedLocalRef<jobjectArray> item(env, env->NewObjectArray(2, objectClass, NULL));
4020
4021        ScopedLocalRef<jobject> type(env, env->CallStaticObjectMethod(integerClass,
4022                integer_valueOfMethod, gen->type));
4023        env->SetObjectArrayElement(item.get(), 0, type.get());
4024        env->SetObjectArrayElement(item.get(), 1, val.get());
4025
4026        env->SetObjectArrayElement(joa.get(), j, item.get());
4027    }
4028
4029    if (count == 0) {
4030        JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to 0; returning NULL",
4031                x509, type, origCount);
4032        joa.reset(NULL);
4033    } else if (origCount != count) {
4034        JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to %d", x509, type,
4035                origCount, count);
4036
4037        ScopedLocalRef<jobjectArray> joa_copy(env, env->NewObjectArray(count, objectArrayClass,
4038                NULL));
4039
4040        for (int i = 0; i < count; i++) {
4041            ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(joa.get(), i));
4042            env->SetObjectArrayElement(joa_copy.get(), i, item.get());
4043        }
4044
4045        joa.reset(joa_copy.release());
4046    }
4047
4048    JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => %d entries", x509, type, count);
4049    return joa.release();
4050}
4051
4052static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref) {
4053    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4054    JNI_TRACE("X509_get_notBefore(%p)", x509);
4055
4056    if (x509 == NULL) {
4057        jniThrowNullPointerException(env, "x509 == null");
4058        JNI_TRACE("X509_get_notBefore(%p) => x509 == null", x509);
4059        return 0;
4060    }
4061
4062    ASN1_TIME* notBefore = X509_get_notBefore(x509);
4063    JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore);
4064    return reinterpret_cast<uintptr_t>(notBefore);
4065}
4066
4067static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref) {
4068    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4069    JNI_TRACE("X509_get_notAfter(%p)", x509);
4070
4071    if (x509 == NULL) {
4072        jniThrowNullPointerException(env, "x509 == null");
4073        JNI_TRACE("X509_get_notAfter(%p) => x509 == null", x509);
4074        return 0;
4075    }
4076
4077    ASN1_TIME* notAfter = X509_get_notAfter(x509);
4078    JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter);
4079    return reinterpret_cast<uintptr_t>(notAfter);
4080}
4081
4082static long NativeCrypto_X509_get_version(JNIEnv*, jclass, jlong x509Ref) {
4083    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4084    JNI_TRACE("X509_get_version(%p)", x509);
4085
4086    long version = X509_get_version(x509);
4087    JNI_TRACE("X509_get_version(%p) => %ld", x509, version);
4088    return version;
4089}
4090
4091template<typename T>
4092static jbyteArray get_X509Type_serialNumber(JNIEnv* env, T* x509Type, ASN1_INTEGER* (*get_serial_func)(T*)) {
4093    JNI_TRACE("get_X509Type_serialNumber(%p)", x509Type);
4094
4095    if (x509Type == NULL) {
4096        jniThrowNullPointerException(env, "x509Type == null");
4097        JNI_TRACE("get_X509Type_serialNumber(%p) => x509Type == null", x509Type);
4098        return NULL;
4099    }
4100
4101    ASN1_INTEGER* serialNumber = get_serial_func(x509Type);
4102    Unique_BIGNUM serialBn(ASN1_INTEGER_to_BN(serialNumber, NULL));
4103    if (serialBn.get() == NULL) {
4104        JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
4105        return NULL;
4106    }
4107
4108    ScopedLocalRef<jbyteArray> serialArray(env, bignumToArray(env, serialBn.get(), "serialBn"));
4109    if (env->ExceptionCheck()) {
4110        JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
4111        return NULL;
4112    }
4113
4114    JNI_TRACE("X509_get_serialNumber(%p) => %p", x509Type, serialArray.get());
4115    return serialArray.release();
4116}
4117
4118/* OpenSSL includes set_serialNumber but not get. */
4119#if !defined(X509_REVOKED_get_serialNumber)
4120static ASN1_INTEGER* X509_REVOKED_get_serialNumber(X509_REVOKED* x) {
4121    return x->serialNumber;
4122}
4123#endif
4124
4125static jbyteArray NativeCrypto_X509_get_serialNumber(JNIEnv* env, jclass, jlong x509Ref) {
4126    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4127    JNI_TRACE("X509_get_serialNumber(%p)", x509);
4128    return get_X509Type_serialNumber<X509>(env, x509, X509_get_serialNumber);
4129}
4130
4131static jbyteArray NativeCrypto_X509_REVOKED_get_serialNumber(JNIEnv* env, jclass, jlong x509RevokedRef) {
4132    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4133    JNI_TRACE("X509_REVOKED_get_serialNumber(%p)", revoked);
4134    return get_X509Type_serialNumber<X509_REVOKED>(env, revoked, X509_REVOKED_get_serialNumber);
4135}
4136
4137static void NativeCrypto_X509_verify(JNIEnv* env, jclass, jlong x509Ref, jlong pkeyRef) {
4138    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4139    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
4140    JNI_TRACE("X509_verify(%p, %p)", x509, pkey);
4141
4142    if (x509 == NULL) {
4143        jniThrowNullPointerException(env, "x509 == null");
4144        JNI_TRACE("X509_verify(%p, %p) => x509 == null", x509, pkey);
4145        return;
4146    }
4147
4148    if (pkey == NULL) {
4149        jniThrowNullPointerException(env, "pkey == null");
4150        JNI_TRACE("X509_verify(%p, %p) => pkey == null", x509, pkey);
4151        return;
4152    }
4153
4154    if (X509_verify(x509, pkey) != 1) {
4155        throwExceptionIfNecessary(env, "X509_verify");
4156        JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey);
4157    } else {
4158        JNI_TRACE("X509_verify(%p, %p) => verify success", x509, pkey);
4159    }
4160}
4161
4162static jbyteArray NativeCrypto_get_X509_cert_info_enc(JNIEnv* env, jclass, jlong x509Ref) {
4163    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4164    JNI_TRACE("get_X509_cert_info_enc(%p)", x509);
4165    return ASN1ToByteArray<X509_CINF, i2d_X509_CINF>(env, x509->cert_info);
4166}
4167
4168static jint NativeCrypto_get_X509_ex_flags(JNIEnv* env, jclass, jlong x509Ref) {
4169    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4170    JNI_TRACE("get_X509_ex_flags(%p)", x509);
4171
4172    if (x509 == NULL) {
4173        jniThrowNullPointerException(env, "x509 == null");
4174        JNI_TRACE("get_X509_ex_flags(%p) => x509 == null", x509);
4175        return 0;
4176    }
4177
4178    X509_check_ca(x509);
4179
4180    return x509->ex_flags;
4181}
4182
4183static jboolean NativeCrypto_X509_check_issued(JNIEnv*, jclass, jlong x509Ref1, jlong x509Ref2) {
4184    X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1));
4185    X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2));
4186    JNI_TRACE("X509_check_issued(%p, %p)", x509_1, x509_2);
4187
4188    int ret = X509_check_issued(x509_1, x509_2);
4189    JNI_TRACE("X509_check_issued(%p, %p) => %d", x509_1, x509_2, ret);
4190    return ret;
4191}
4192
4193static void get_X509_signature(X509 *x509, ASN1_BIT_STRING** signature) {
4194    *signature = x509->signature;
4195}
4196
4197static void get_X509_CRL_signature(X509_CRL *crl, ASN1_BIT_STRING** signature) {
4198    *signature = crl->signature;
4199}
4200
4201template<typename T>
4202static jbyteArray get_X509Type_signature(JNIEnv* env, T* x509Type, void (*get_signature_func)(T*, ASN1_BIT_STRING**)) {
4203    JNI_TRACE("get_X509Type_signature(%p)", x509Type);
4204
4205    if (x509Type == NULL) {
4206        jniThrowNullPointerException(env, "x509Type == null");
4207        JNI_TRACE("get_X509Type_signature(%p) => x509Type == null", x509Type);
4208        return NULL;
4209    }
4210
4211    ASN1_BIT_STRING* signature;
4212    get_signature_func(x509Type, &signature);
4213
4214    ScopedLocalRef<jbyteArray> signatureArray(env, env->NewByteArray(signature->length));
4215    if (env->ExceptionCheck()) {
4216        JNI_TRACE("get_X509Type_signature(%p) => threw exception", x509Type);
4217        return NULL;
4218    }
4219
4220    ScopedByteArrayRW signatureBytes(env, signatureArray.get());
4221    if (signatureBytes.get() == NULL) {
4222        JNI_TRACE("get_X509Type_signature(%p) => using byte array failed", x509Type);
4223        return NULL;
4224    }
4225
4226    memcpy(signatureBytes.get(), signature->data, signature->length);
4227
4228    JNI_TRACE("get_X509Type_signature(%p) => %p (%d bytes)", x509Type, signatureArray.get(),
4229            signature->length);
4230    return signatureArray.release();
4231}
4232
4233static jbyteArray NativeCrypto_get_X509_signature(JNIEnv* env, jclass, jlong x509Ref) {
4234    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4235    JNI_TRACE("get_X509_signature(%p)", x509);
4236    return get_X509Type_signature<X509>(env, x509, get_X509_signature);
4237}
4238
4239static jbyteArray NativeCrypto_get_X509_CRL_signature(JNIEnv* env, jclass, jlong x509CrlRef) {
4240    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4241    JNI_TRACE("get_X509_CRL_signature(%p)", crl);
4242    return get_X509Type_signature<X509_CRL>(env, crl, get_X509_CRL_signature);
4243}
4244
4245static jlong NativeCrypto_X509_CRL_get0_by_cert(JNIEnv* env, jclass, jlong x509crlRef, jlong x509Ref) {
4246    X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
4247    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4248    JNI_TRACE("X509_CRL_get0_by_cert(%p, %p)", x509crl, x509);
4249
4250    if (x509crl == NULL) {
4251        jniThrowNullPointerException(env, "x509crl == null");
4252        JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509crl == null", x509crl, x509);
4253        return 0;
4254    } else if (x509 == NULL) {
4255        jniThrowNullPointerException(env, "x509 == null");
4256        JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509 == null", x509crl, x509);
4257        return 0;
4258    }
4259
4260    X509_REVOKED* revoked = NULL;
4261    int ret = X509_CRL_get0_by_cert(x509crl, &revoked, x509);
4262    if (ret == 0) {
4263        JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => none", x509crl, x509);
4264        return 0;
4265    }
4266
4267    JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, x509, revoked);
4268    return reinterpret_cast<uintptr_t>(revoked);
4269}
4270
4271static jlong NativeCrypto_X509_CRL_get0_by_serial(JNIEnv* env, jclass, jlong x509crlRef, jbyteArray serialArray) {
4272    X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
4273    JNI_TRACE("X509_CRL_get0_by_serial(%p, %p)", x509crl, serialArray);
4274
4275    if (x509crl == NULL) {
4276        jniThrowNullPointerException(env, "x509crl == null");
4277        JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => crl == null", x509crl, serialArray);
4278        return 0;
4279    }
4280
4281    Unique_BIGNUM serialBn(BN_new());
4282    if (serialBn.get() == NULL) {
4283        JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN allocation failed", x509crl, serialArray);
4284        return 0;
4285    }
4286
4287    BIGNUM* serialBare = serialBn.get();
4288    if (!arrayToBignum(env, serialArray, &serialBare)) {
4289        if (!env->ExceptionCheck()) {
4290            jniThrowNullPointerException(env, "serial == null");
4291        }
4292        JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
4293        return 0;
4294    }
4295
4296    Unique_ASN1_INTEGER serialInteger(BN_to_ASN1_INTEGER(serialBn.get(), NULL));
4297    if (serialInteger.get() == NULL) {
4298        JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
4299        return 0;
4300    }
4301
4302    X509_REVOKED* revoked = NULL;
4303    int ret = X509_CRL_get0_by_serial(x509crl, &revoked, serialInteger.get());
4304    if (ret == 0) {
4305        JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => none", x509crl, serialArray);
4306        return 0;
4307    }
4308
4309    JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, serialArray, revoked);
4310    return reinterpret_cast<uintptr_t>(revoked);
4311}
4312
4313
4314/* This appears to be missing from OpenSSL. */
4315#if !defined(X509_REVOKED_dup)
4316X509_REVOKED* X509_REVOKED_dup(X509_REVOKED* x) {
4317    return reinterpret_cast<X509_REVOKED*>(ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), x));
4318}
4319#endif
4320
4321static jlongArray NativeCrypto_X509_CRL_get_REVOKED(JNIEnv* env, jclass, jlong x509CrlRef) {
4322    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4323    JNI_TRACE("X509_CRL_get_REVOKED(%p)", crl);
4324
4325    if (crl == NULL) {
4326        jniThrowNullPointerException(env, "crl == null");
4327        return NULL;
4328    }
4329
4330    STACK_OF(X509_REVOKED)* stack = X509_CRL_get_REVOKED(crl);
4331    if (stack == NULL) {
4332        JNI_TRACE("X509_CRL_get_REVOKED(%p) => stack is null", crl);
4333        return NULL;
4334    }
4335
4336    size_t size = sk_X509_REVOKED_num(stack);
4337
4338    ScopedLocalRef<jlongArray> revokedArray(env, env->NewLongArray(size));
4339    ScopedLongArrayRW revoked(env, revokedArray.get());
4340    for (size_t i = 0; i < size; i++) {
4341        X509_REVOKED* item = reinterpret_cast<X509_REVOKED*>(sk_X509_REVOKED_value(stack, i));
4342        revoked[i] = reinterpret_cast<uintptr_t>(X509_REVOKED_dup(item));
4343    }
4344
4345    JNI_TRACE("X509_CRL_get_REVOKED(%p) => %p [size=%d]", stack, revokedArray.get(), size);
4346    return revokedArray.release();
4347}
4348
4349static jbyteArray NativeCrypto_i2d_X509_CRL(JNIEnv* env, jclass, jlong x509CrlRef) {
4350    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4351    JNI_TRACE("i2d_X509_CRL(%p)", crl);
4352    return ASN1ToByteArray<X509_CRL, i2d_X509_CRL>(env, crl);
4353}
4354
4355static void NativeCrypto_X509_CRL_free(JNIEnv* env, jclass, jlong x509CrlRef) {
4356    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4357    JNI_TRACE("X509_CRL_free(%p)", crl);
4358
4359    if (crl == NULL) {
4360        jniThrowNullPointerException(env, "crl == null");
4361        JNI_TRACE("X509_CRL_free(%p) => crl == null", crl);
4362        return;
4363    }
4364
4365    X509_CRL_free(crl);
4366}
4367
4368static void NativeCrypto_X509_CRL_print(JNIEnv* env, jclass, jlong bioRef, jlong x509CrlRef) {
4369    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4370    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4371    JNI_TRACE("X509_CRL_print(%p, %p)", bio, crl);
4372
4373    if (bio == NULL) {
4374        jniThrowNullPointerException(env, "bio == null");
4375        JNI_TRACE("X509_CRL_print(%p, %p) => bio == null", bio, crl);
4376        return;
4377    }
4378
4379    if (crl == NULL) {
4380        jniThrowNullPointerException(env, "crl == null");
4381        JNI_TRACE("X509_CRL_print(%p, %p) => crl == null", bio, crl);
4382        return;
4383    }
4384
4385    if (!X509_CRL_print(bio, crl)) {
4386        throwExceptionIfNecessary(env, "X509_CRL_print");
4387        JNI_TRACE("X509_CRL_print(%p, %p) => threw error", bio, crl);
4388    } else {
4389        JNI_TRACE("X509_CRL_print(%p, %p) => success", bio, crl);
4390    }
4391}
4392
4393static jstring NativeCrypto_get_X509_CRL_sig_alg_oid(JNIEnv* env, jclass, jlong x509CrlRef) {
4394    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4395    JNI_TRACE("get_X509_CRL_sig_alg_oid(%p)", crl);
4396
4397    if (crl == NULL || crl->sig_alg == NULL) {
4398        jniThrowNullPointerException(env, "crl == NULL || crl->sig_alg == NULL");
4399        JNI_TRACE("get_X509_CRL_sig_alg_oid(%p) => crl == NULL", crl);
4400        return NULL;
4401    }
4402
4403    return ASN1_OBJECT_to_OID_string(env, crl->sig_alg->algorithm);
4404}
4405
4406static jbyteArray NativeCrypto_get_X509_CRL_sig_alg_parameter(JNIEnv* env, jclass, jlong x509CrlRef) {
4407    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4408    JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p)", crl);
4409
4410    if (crl == NULL) {
4411        jniThrowNullPointerException(env, "crl == null");
4412        JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => crl == null", crl);
4413        return NULL;
4414    }
4415
4416    if (crl->sig_alg->parameter == NULL) {
4417        JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => null", crl);
4418        return NULL;
4419    }
4420
4421    return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, crl->sig_alg->parameter);
4422}
4423
4424static jbyteArray NativeCrypto_X509_CRL_get_issuer_name(JNIEnv* env, jclass, jlong x509CrlRef) {
4425    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4426    JNI_TRACE("X509_CRL_get_issuer_name(%p)", crl);
4427    return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_CRL_get_issuer(crl));
4428}
4429
4430static long NativeCrypto_X509_CRL_get_version(JNIEnv*, jclass, jlong x509CrlRef) {
4431    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4432    JNI_TRACE("X509_CRL_get_version(%p)", crl);
4433
4434    long version = X509_CRL_get_version(crl);
4435    JNI_TRACE("X509_CRL_get_version(%p) => %ld", crl, version);
4436    return version;
4437}
4438
4439template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
4440        X509_EXTENSION* (*get_ext_func)(T*, int)>
4441static X509_EXTENSION *X509Type_get_ext(JNIEnv* env, T* x509Type, jstring oidString) {
4442    JNI_TRACE("X509Type_get_ext(%p)", x509Type);
4443
4444    if (x509Type == NULL) {
4445        jniThrowNullPointerException(env, "x509 == null");
4446        return NULL;
4447    }
4448
4449    ScopedUtfChars oid(env, oidString);
4450    if (oid.c_str() == NULL) {
4451        return NULL;
4452    }
4453
4454    Unique_ASN1_OBJECT asn1(OBJ_txt2obj(oid.c_str(), 1));
4455    if (asn1.get() == NULL) {
4456        JNI_TRACE("X509Type_get_ext(%p, %s) => oid conversion failed", x509Type, oid.c_str());
4457        freeOpenSslErrorState();
4458        return NULL;
4459    }
4460
4461    int extIndex = get_ext_by_OBJ_func(x509Type, asn1.get(), -1);
4462    if (extIndex == -1) {
4463        JNI_TRACE("X509Type_get_ext(%p, %s) => ext not found", x509Type, oid.c_str());
4464        return NULL;
4465    }
4466
4467    X509_EXTENSION* ext = get_ext_func(x509Type, extIndex);
4468    JNI_TRACE("X509Type_get_ext(%p, %s) => %p", x509Type, oid.c_str(), ext);
4469    return ext;
4470}
4471
4472template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
4473        X509_EXTENSION* (*get_ext_func)(T*, int)>
4474static jbyteArray X509Type_get_ext_oid(JNIEnv* env, T* x509Type, jstring oidString) {
4475    X509_EXTENSION* ext = X509Type_get_ext<T, get_ext_by_OBJ_func, get_ext_func>(env, x509Type,
4476            oidString);
4477    if (ext == NULL) {
4478        JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString);
4479        return NULL;
4480    }
4481
4482    JNI_TRACE("X509Type_get_ext_oid(%p, %p) => %p", x509Type, oidString, ext->value);
4483    return ASN1ToByteArray<ASN1_OCTET_STRING, i2d_ASN1_OCTET_STRING>(env, ext->value);
4484}
4485
4486static jint NativeCrypto_X509_CRL_get_ext(JNIEnv* env, jclass, jlong x509CrlRef, jstring oid) {
4487    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4488    JNI_TRACE("X509_CRL_get_ext(%p, %p)", crl, oid);
4489    X509_EXTENSION* ext = X509Type_get_ext<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(
4490            env, crl, oid);
4491    JNI_TRACE("X509_CRL_get_ext(%p, %p) => %p", crl, oid, ext);
4492    return reinterpret_cast<uintptr_t>(ext);
4493}
4494
4495static jint NativeCrypto_X509_REVOKED_get_ext(JNIEnv* env, jclass, jlong x509RevokedRef,
4496        jstring oid) {
4497    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4498    JNI_TRACE("X509_REVOKED_get_ext(%p, %p)", revoked, oid);
4499    X509_EXTENSION* ext = X509Type_get_ext<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ,
4500            X509_REVOKED_get_ext>(env, revoked, oid);
4501    JNI_TRACE("X509_REVOKED_get_ext(%p, %p) => %p", revoked, oid, ext);
4502    return reinterpret_cast<uintptr_t>(ext);
4503}
4504
4505static jlong NativeCrypto_X509_REVOKED_dup(JNIEnv* env, jclass, jlong x509RevokedRef) {
4506    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4507    JNI_TRACE("X509_REVOKED_dup(%p)", revoked);
4508
4509    if (revoked == NULL) {
4510        jniThrowNullPointerException(env, "revoked == null");
4511        JNI_TRACE("X509_REVOKED_dup(%p) => revoked == null", revoked);
4512        return 0;
4513    }
4514
4515    X509_REVOKED* dup = X509_REVOKED_dup(revoked);
4516    JNI_TRACE("X509_REVOKED_dup(%p) => %p", revoked, dup);
4517    return reinterpret_cast<uintptr_t>(dup);
4518}
4519
4520static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass, jlong x509RevokedRef) {
4521    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4522    JNI_TRACE("get_X509_REVOKED_revocationDate(%p)", revoked);
4523
4524    if (revoked == NULL) {
4525        jniThrowNullPointerException(env, "revoked == null");
4526        JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => revoked == null", revoked);
4527        return 0;
4528    }
4529
4530    JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked, revoked->revocationDate);
4531    return reinterpret_cast<uintptr_t>(revoked->revocationDate);
4532}
4533
4534#pragma GCC diagnostic push
4535#pragma GCC diagnostic ignored "-Wwrite-strings"
4536static void NativeCrypto_X509_REVOKED_print(JNIEnv* env, jclass, jlong bioRef, jlong x509RevokedRef) {
4537    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4538    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4539    JNI_TRACE("X509_REVOKED_print(%p, %p)", bio, revoked);
4540
4541    if (bio == NULL) {
4542        jniThrowNullPointerException(env, "bio == null");
4543        JNI_TRACE("X509_REVOKED_print(%p, %p) => bio == null", bio, revoked);
4544        return;
4545    }
4546
4547    if (revoked == NULL) {
4548        jniThrowNullPointerException(env, "revoked == null");
4549        JNI_TRACE("X509_REVOKED_print(%p, %p) => revoked == null", bio, revoked);
4550        return;
4551    }
4552
4553    BIO_printf(bio, "Serial Number: ");
4554    i2a_ASN1_INTEGER(bio, revoked->serialNumber);
4555    BIO_printf(bio, "\nRevocation Date: ");
4556    ASN1_TIME_print(bio, revoked->revocationDate);
4557    BIO_printf(bio, "\n");
4558    X509V3_extensions_print(bio, "CRL entry extensions", revoked->extensions, 0, 0);
4559}
4560#pragma GCC diagnostic pop
4561
4562static jbyteArray NativeCrypto_get_X509_CRL_crl_enc(JNIEnv* env, jclass, jlong x509CrlRef) {
4563    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4564    JNI_TRACE("get_X509_CRL_crl_enc(%p)", crl);
4565    return ASN1ToByteArray<X509_CRL_INFO, i2d_X509_CRL_INFO>(env, crl->crl);
4566}
4567
4568static void NativeCrypto_X509_CRL_verify(JNIEnv* env, jclass, jlong x509CrlRef, jlong pkeyRef) {
4569    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4570    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
4571    JNI_TRACE("X509_CRL_verify(%p, %p)", crl, pkey);
4572
4573    if (crl == NULL) {
4574        jniThrowNullPointerException(env, "crl == null");
4575        JNI_TRACE("X509_CRL_verify(%p, %p) => crl == null", crl, pkey);
4576        return;
4577    }
4578
4579    if (pkey == NULL) {
4580        jniThrowNullPointerException(env, "pkey == null");
4581        JNI_TRACE("X509_CRL_verify(%p, %p) => pkey == null", crl, pkey);
4582        return;
4583    }
4584
4585    if (X509_CRL_verify(crl, pkey) != 1) {
4586        throwExceptionIfNecessary(env, "X509_CRL_verify");
4587        JNI_TRACE("X509_CRL_verify(%p, %p) => verify failure", crl, pkey);
4588    } else {
4589        JNI_TRACE("X509_CRL_verify(%p, %p) => verify success", crl, pkey);
4590    }
4591}
4592
4593static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
4594    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4595    JNI_TRACE("X509_CRL_get_lastUpdate(%p)", crl);
4596
4597    if (crl == NULL) {
4598        jniThrowNullPointerException(env, "crl == null");
4599        JNI_TRACE("X509_CRL_get_lastUpdate(%p) => crl == null", crl);
4600        return 0;
4601    }
4602
4603    ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl);
4604    JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate);
4605    return reinterpret_cast<uintptr_t>(lastUpdate);
4606}
4607
4608static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
4609    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
4610    JNI_TRACE("X509_CRL_get_nextUpdate(%p)", crl);
4611
4612    if (crl == NULL) {
4613        jniThrowNullPointerException(env, "crl == null");
4614        JNI_TRACE("X509_CRL_get_nextUpdate(%p) => crl == null", crl);
4615        return 0;
4616    }
4617
4618    ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl);
4619    JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate);
4620    return reinterpret_cast<uintptr_t>(nextUpdate);
4621}
4622
4623static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) {
4624    X509_REVOKED* x509Revoked =
4625            reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
4626    JNI_TRACE("i2d_X509_REVOKED(%p)", x509Revoked);
4627    return ASN1ToByteArray<X509_REVOKED, i2d_X509_REVOKED>(env, x509Revoked);
4628}
4629
4630static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x509ExtensionRef) {
4631    X509_EXTENSION* ext = reinterpret_cast<X509_EXTENSION*>(static_cast<uintptr_t>(x509ExtensionRef));
4632
4633    if (ext == NULL) {
4634        jniThrowNullPointerException(env, "ext == NULL");
4635        return 0;
4636    }
4637
4638    return X509_supported_extension(ext);
4639}
4640
4641static inline void get_ASN1_TIME_data(char **data, int* output, size_t len) {
4642    char c = **data;
4643    **data = '\0';
4644    *data -= len;
4645    *output = atoi(*data);
4646    *(*data + len) = c;
4647}
4648
4649static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef, jobject calendar) {
4650    ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef));
4651    JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar);
4652
4653    if (asn1Time == NULL) {
4654        jniThrowNullPointerException(env, "asn1Time == null");
4655        return;
4656    }
4657
4658    Unique_ASN1_GENERALIZEDTIME gen(ASN1_TIME_to_generalizedtime(asn1Time, NULL));
4659    if (gen.get() == NULL) {
4660        jniThrowNullPointerException(env, "asn1Time == null");
4661        return;
4662    }
4663
4664    if (gen->length < 14 || gen->data == NULL) {
4665        jniThrowNullPointerException(env, "gen->length < 14 || gen->data == NULL");
4666        return;
4667    }
4668
4669    int sec, min, hour, mday, mon, year;
4670
4671    char *p = (char*) &gen->data[14];
4672
4673    get_ASN1_TIME_data(&p, &sec, 2);
4674    get_ASN1_TIME_data(&p, &min, 2);
4675    get_ASN1_TIME_data(&p, &hour, 2);
4676    get_ASN1_TIME_data(&p, &mday, 2);
4677    get_ASN1_TIME_data(&p, &mon, 2);
4678    get_ASN1_TIME_data(&p, &year, 4);
4679
4680    env->CallVoidMethod(calendar, calendar_setMethod, year, mon - 1, mday, hour, min, sec);
4681}
4682
4683static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) {
4684    JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr);
4685
4686    ScopedUtfChars oid(env, oidStr);
4687    if (oid.c_str() == NULL) {
4688        return NULL;
4689    }
4690
4691    JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str());
4692
4693    int nid = OBJ_txt2nid(oid.c_str());
4694    if (nid == NID_undef) {
4695        JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str());
4696        freeOpenSslErrorState();
4697        return NULL;
4698    }
4699
4700    Unique_ASN1_OBJECT obj(OBJ_nid2obj(nid));
4701    if (obj.get() == NULL) {
4702        throwExceptionIfNecessary(env, "OBJ_nid2obj");
4703        return NULL;
4704    }
4705
4706    ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj.get()));
4707    JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get());
4708    return ouputStr.release();
4709}
4710
4711static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) {
4712    X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef));
4713    unsigned long flags = static_cast<unsigned long>(jflags);
4714    JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags);
4715
4716    if (x509name == NULL) {
4717        jniThrowNullPointerException(env, "x509name == null");
4718        JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags);
4719        return NULL;
4720    }
4721
4722    return X509_NAME_to_jstring(env, x509name, flags);
4723}
4724
4725template <typename T, T* (*d2i_func)(BIO*, T**)>
4726static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
4727    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4728    JNI_TRACE("d2i_ASN1Object_to_jlong(%p)", bio);
4729
4730    if (bio == NULL) {
4731        jniThrowNullPointerException(env, "bio == null");
4732        return 0;
4733    }
4734
4735    T* x = d2i_func(bio, NULL);
4736    if (x == NULL) {
4737        throwExceptionIfNecessary(env, "d2i_ASN1Object_to_jlong");
4738        return 0;
4739    }
4740
4741    return reinterpret_cast<uintptr_t>(x);
4742}
4743
4744static jlong NativeCrypto_d2i_X509_CRL_bio(JNIEnv* env, jclass, jlong bioRef) {
4745    return d2i_ASN1Object_to_jlong<X509_CRL, d2i_X509_CRL_bio>(env, bioRef);
4746}
4747
4748static jlong NativeCrypto_d2i_X509_bio(JNIEnv* env, jclass, jlong bioRef) {
4749    return d2i_ASN1Object_to_jlong<X509, d2i_X509_bio>(env, bioRef);
4750}
4751
4752static jlong NativeCrypto_d2i_X509(JNIEnv* env, jclass, jbyteArray certBytes) {
4753    X509* x = ByteArrayToASN1<X509, d2i_X509>(env, certBytes);
4754    return reinterpret_cast<uintptr_t>(x);
4755}
4756
4757static jbyteArray NativeCrypto_i2d_X509(JNIEnv* env, jclass, jlong x509Ref) {
4758    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4759    JNI_TRACE("i2d_X509(%p)", x509);
4760    return ASN1ToByteArray<X509, i2d_X509>(env, x509);
4761}
4762
4763static jbyteArray NativeCrypto_i2d_X509_PUBKEY(JNIEnv* env, jclass, jlong x509Ref) {
4764    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
4765    JNI_TRACE("i2d_X509_PUBKEY(%p)", x509);
4766    return ASN1ToByteArray<X509_PUBKEY, i2d_X509_PUBKEY>(env, X509_get_X509_PUBKEY(x509));
4767}
4768
4769
4770template<typename T, T* (*PEM_read_func)(BIO*, T**, pem_password_cb*, void*)>
4771static jlong PEM_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
4772    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4773    JNI_TRACE("PEM_ASN1Object_to_jlong(%p)", bio);
4774
4775    if (bio == NULL) {
4776        jniThrowNullPointerException(env, "bio == null");
4777        JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => bio == null", bio);
4778        return 0;
4779    }
4780
4781    T* x = PEM_read_func(bio, NULL, NULL, NULL);
4782    if (x == NULL) {
4783        throwExceptionIfNecessary(env, "PEM_ASN1Object_to_jlong");
4784        // Sometimes the PEM functions fail without pushing an error
4785        if (!env->ExceptionCheck()) {
4786            jniThrowRuntimeException(env, "Failure parsing PEM");
4787        }
4788        JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => threw exception", bio);
4789        return 0;
4790    }
4791
4792    JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => %p", bio, x);
4793    return reinterpret_cast<uintptr_t>(x);
4794}
4795
4796static jlong NativeCrypto_PEM_read_bio_X509(JNIEnv* env, jclass, jlong bioRef) {
4797    JNI_TRACE("PEM_read_bio_X509(0x%llx)", bioRef);
4798    return PEM_ASN1Object_to_jlong<X509, PEM_read_bio_X509>(env, bioRef);
4799}
4800
4801static jlong NativeCrypto_PEM_read_bio_X509_CRL(JNIEnv* env, jclass, jlong bioRef) {
4802    JNI_TRACE("PEM_read_bio_X509_CRL(0x%llx)", bioRef);
4803    return PEM_ASN1Object_to_jlong<X509_CRL, PEM_read_bio_X509_CRL>(env, bioRef);
4804}
4805
4806static STACK_OF(X509)* PKCS7_get_certs(PKCS7* pkcs7) {
4807    if (PKCS7_type_is_signed(pkcs7)) {
4808        return pkcs7->d.sign->cert;
4809    } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) {
4810        return pkcs7->d.signed_and_enveloped->cert;
4811    } else {
4812        JNI_TRACE("PKCS7_get_certs(%p) => unknown PKCS7 type", pkcs7);
4813        return NULL;
4814    }
4815}
4816
4817static STACK_OF(X509_CRL)* PKCS7_get_CRLs(PKCS7* pkcs7) {
4818    if (PKCS7_type_is_signed(pkcs7)) {
4819        return pkcs7->d.sign->crl;
4820    } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) {
4821        return pkcs7->d.signed_and_enveloped->crl;
4822    } else {
4823        JNI_TRACE("PKCS7_get_CRLs(%p) => unknown PKCS7 type", pkcs7);
4824        return NULL;
4825    }
4826}
4827
4828template <typename T, typename T_stack>
4829static jlongArray PKCS7_to_ItemArray(JNIEnv* env, T_stack* stack, T* (*dup_func)(T*))
4830{
4831    if (stack == NULL) {
4832        return NULL;
4833    }
4834
4835    ScopedLocalRef<jlongArray> ref_array(env, NULL);
4836    size_t size = sk_num(reinterpret_cast<_STACK*>(stack));
4837    ref_array.reset(env->NewLongArray(size));
4838    ScopedLongArrayRW items(env, ref_array.get());
4839    for (size_t i = 0; i < size; i++) {
4840        T* item = reinterpret_cast<T*>(sk_value(reinterpret_cast<_STACK*>(stack), i));
4841        items[i] = reinterpret_cast<uintptr_t>(dup_func(item));
4842    }
4843
4844    JNI_TRACE("PKCS7_to_ItemArray(%p) => %p [size=%d]", stack, ref_array.get(), size);
4845    return ref_array.release();
4846}
4847
4848#define PKCS7_CERTS 1
4849#define PKCS7_CRLS 2
4850
4851static jlongArray NativeCrypto_PEM_read_bio_PKCS7(JNIEnv* env, jclass, jlong bioRef, jint which) {
4852    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4853    JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p)", bio);
4854
4855    if (bio == NULL) {
4856        jniThrowNullPointerException(env, "bio == null");
4857        JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => bio == null", bio);
4858        return 0;
4859    }
4860
4861    Unique_PKCS7 pkcs7(PEM_read_bio_PKCS7(bio, NULL, NULL, NULL));
4862    if (pkcs7.get() == NULL) {
4863        throwExceptionIfNecessary(env, "PEM_read_bio_PKCS7_CRLs");
4864        JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => threw exception", bio);
4865        return 0;
4866    }
4867
4868    switch (which) {
4869    case PKCS7_CERTS:
4870        return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup);
4871    case PKCS7_CRLS:
4872        return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()),
4873                X509_CRL_dup);
4874    default:
4875        jniThrowRuntimeException(env, "unknown PKCS7 field");
4876        return NULL;
4877    }
4878}
4879
4880static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, jint which) {
4881    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4882    JNI_TRACE("d2i_PKCS7_bio(%p, %d)", bio, which);
4883
4884    if (bio == NULL) {
4885        jniThrowNullPointerException(env, "bio == null");
4886        JNI_TRACE("d2i_PKCS7_bio(%p, %d) => bio == null", bio, which);
4887        return 0;
4888    }
4889
4890    Unique_PKCS7 pkcs7(d2i_PKCS7_bio(bio, NULL));
4891    if (pkcs7.get() == NULL) {
4892        throwExceptionIfNecessary(env, "d2i_PKCS7_bio");
4893        JNI_TRACE("d2i_PKCS7_bio(%p, %d) => threw exception", bio, which);
4894        return 0;
4895    }
4896
4897    switch (which) {
4898    case PKCS7_CERTS:
4899        return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup);
4900    case PKCS7_CRLS:
4901        return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()),
4902                X509_CRL_dup);
4903    default:
4904        jniThrowRuntimeException(env, "unknown PKCS7 field");
4905        return NULL;
4906    }
4907}
4908
4909static jbyteArray NativeCrypto_i2d_PKCS7(JNIEnv* env, jclass, jlongArray certsArray) {
4910    JNI_TRACE("i2d_PKCS7(%p)", certsArray);
4911
4912    Unique_PKCS7 pkcs7(PKCS7_new());
4913    if (pkcs7.get() == NULL) {
4914        jniThrowNullPointerException(env, "pkcs7 == null");
4915        JNI_TRACE("i2d_PKCS7(%p) => pkcs7 == null", certsArray);
4916        return NULL;
4917    }
4918
4919    if (PKCS7_set_type(pkcs7.get(), NID_pkcs7_signed) != 1) {
4920        throwExceptionIfNecessary(env, "PKCS7_set_type");
4921        return NULL;
4922    }
4923
4924    ScopedLongArrayRO certs(env, certsArray);
4925    for (size_t i = 0; i < certs.size(); i++) {
4926        X509* item = reinterpret_cast<X509*>(certs[i]);
4927        if (PKCS7_add_certificate(pkcs7.get(), item) != 1) {
4928            throwExceptionIfNecessary(env, "i2d_PKCS7");
4929            return NULL;
4930        }
4931    }
4932
4933    JNI_TRACE("i2d_PKCS7(%p) => %d certs", certsArray, certs.size());
4934    return ASN1ToByteArray<PKCS7, i2d_PKCS7>(env, pkcs7.get());
4935}
4936
4937typedef STACK_OF(X509) PKIPATH;
4938
4939ASN1_ITEM_TEMPLATE(PKIPATH) =
4940    ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, PkiPath, X509)
4941ASN1_ITEM_TEMPLATE_END(PKIPATH)
4942
4943static jlongArray NativeCrypto_ASN1_seq_unpack_X509_bio(JNIEnv* env, jclass, jlong bioRef) {
4944    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
4945    JNI_TRACE("ASN1_seq_unpack_X509_bio(%p)", bio);
4946
4947    Unique_sk_X509 path((PKIPATH*) ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKIPATH), bio, NULL));
4948    if (path.get() == NULL) {
4949        throwExceptionIfNecessary(env, "ASN1_seq_unpack_X509_bio");
4950        return NULL;
4951    }
4952
4953    size_t size = sk_X509_num(path.get());
4954
4955    ScopedLocalRef<jlongArray> certArray(env, env->NewLongArray(size));
4956    ScopedLongArrayRW certs(env, certArray.get());
4957    for (size_t i = 0; i < size; i++) {
4958        X509* item = reinterpret_cast<X509*>(sk_X509_shift(path.get()));
4959        certs[i] = reinterpret_cast<uintptr_t>(item);
4960    }
4961
4962    JNI_TRACE("ASN1_seq_unpack_X509_bio(%p) => returns %d items", bio, size);
4963    return certArray.release();
4964}
4965
4966static jbyteArray NativeCrypto_ASN1_seq_pack_X509(JNIEnv* env, jclass, jlongArray certs) {
4967    JNI_TRACE("ASN1_seq_pack_X509(%p)", certs);
4968    ScopedLongArrayRO certsArray(env, certs);
4969    if (certsArray.get() == NULL) {
4970        JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to get certs array", certs);
4971        return NULL;
4972    }
4973
4974    Unique_sk_X509 certStack(sk_X509_new_null());
4975    if (certStack.get() == NULL) {
4976        JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to make cert stack", certs);
4977        return NULL;
4978    }
4979
4980    for (size_t i = 0; i < certsArray.size(); i++) {
4981        X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(certsArray[i]));
4982        sk_X509_push(certStack.get(), X509_dup_nocopy(x509));
4983    }
4984
4985    int len;
4986    Unique_OPENSSL_str encoded(ASN1_seq_pack(
4987                    reinterpret_cast<STACK_OF(OPENSSL_BLOCK)*>(
4988                            reinterpret_cast<uintptr_t>(certStack.get())),
4989                    reinterpret_cast<int (*)(void*, unsigned char**)>(i2d_X509), NULL, &len));
4990    if (encoded.get() == NULL) {
4991        JNI_TRACE("ASN1_seq_pack_X509(%p) => trouble encoding", certs);
4992        return NULL;
4993    }
4994
4995    ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(len));
4996    if (byteArray.get() == NULL) {
4997        JNI_TRACE("ASN1_seq_pack_X509(%p) => creating byte array failed", certs);
4998        return NULL;
4999    }
5000
5001    ScopedByteArrayRW bytes(env, byteArray.get());
5002    if (bytes.get() == NULL) {
5003        JNI_TRACE("ASN1_seq_pack_X509(%p) => using byte array failed", certs);
5004        return NULL;
5005    }
5006
5007    unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
5008    memcpy(p, encoded.get(), len);
5009
5010    return byteArray.release();
5011}
5012
5013static void NativeCrypto_X509_free(JNIEnv* env, jclass, jlong x509Ref) {
5014    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5015    JNI_TRACE("X509_free(%p)", x509);
5016
5017    if (x509 == NULL) {
5018        jniThrowNullPointerException(env, "x509 == null");
5019        JNI_TRACE("X509_free(%p) => x509 == null", x509);
5020        return;
5021    }
5022
5023    X509_free(x509);
5024}
5025
5026static jint NativeCrypto_X509_cmp(JNIEnv* env, jclass, jlong x509Ref1, jlong x509Ref2) {
5027    X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1));
5028    X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2));
5029    JNI_TRACE("X509_cmp(%p, %p)", x509_1, x509_2);
5030
5031    if (x509_1 == NULL) {
5032        jniThrowNullPointerException(env, "x509_1 == null");
5033        JNI_TRACE("X509_cmp(%p, %p) => x509_1 == null", x509_1, x509_2);
5034        return -1;
5035    }
5036
5037    if (x509_2 == NULL) {
5038        jniThrowNullPointerException(env, "x509_2 == null");
5039        JNI_TRACE("X509_cmp(%p, %p) => x509_2 == null", x509_1, x509_2);
5040        return -1;
5041    }
5042
5043    int ret = X509_cmp(x509_1, x509_2);
5044    JNI_TRACE("X509_cmp(%p, %p) => %d", x509_1, x509_2, ret);
5045    return ret;
5046}
5047
5048static jint NativeCrypto_get_X509_hashCode(JNIEnv* env, jclass, jlong x509Ref) {
5049    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5050
5051    if (x509 == NULL) {
5052        jniThrowNullPointerException(env, "x509 == null");
5053        JNI_TRACE("get_X509_hashCode(%p) => x509 == null", x509);
5054        return 0;
5055    }
5056
5057    // Force caching extensions.
5058    X509_check_ca(x509);
5059
5060    jint hashCode = 0L;
5061    for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
5062        hashCode = 31 * hashCode + x509->sha1_hash[i];
5063    }
5064    return hashCode;
5065}
5066
5067static void NativeCrypto_X509_print_ex(JNIEnv* env, jclass, jlong bioRef, jlong x509Ref,
5068        jlong nmflagJava, jlong certflagJava) {
5069    BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
5070    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5071    long nmflag = static_cast<long>(nmflagJava);
5072    long certflag = static_cast<long>(certflagJava);
5073    JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld)", bio, x509, nmflag, certflag);
5074
5075    if (bio == NULL) {
5076        jniThrowNullPointerException(env, "bio == null");
5077        JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => bio == null", bio, x509, nmflag, certflag);
5078        return;
5079    }
5080
5081    if (x509 == NULL) {
5082        jniThrowNullPointerException(env, "x509 == null");
5083        JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => x509 == null", bio, x509, nmflag, certflag);
5084        return;
5085    }
5086
5087    if (!X509_print_ex(bio, x509, nmflag, certflag)) {
5088        throwExceptionIfNecessary(env, "X509_print_ex");
5089        JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => threw error", bio, x509, nmflag, certflag);
5090    } else {
5091        JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => success", bio, x509, nmflag, certflag);
5092    }
5093}
5094
5095static jlong NativeCrypto_X509_get_pubkey(JNIEnv* env, jclass, jlong x509Ref) {
5096    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5097    JNI_TRACE("X509_get_pubkey(%p)", x509);
5098
5099    if (x509 == NULL) {
5100        jniThrowNullPointerException(env, "x509 == null");
5101        JNI_TRACE("X509_get_pubkey(%p) => x509 == null", x509);
5102        return 0;
5103    }
5104
5105    Unique_EVP_PKEY pkey(X509_get_pubkey(x509));
5106    if (pkey.get() == NULL) {
5107        throwExceptionIfNecessary(env, "X509_get_pubkey");
5108        return 0;
5109    }
5110
5111    return reinterpret_cast<uintptr_t>(pkey.release());
5112}
5113
5114static jbyteArray NativeCrypto_X509_get_issuer_name(JNIEnv* env, jclass, jlong x509Ref) {
5115    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5116    JNI_TRACE("X509_get_issuer_name(%p)", x509);
5117    return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_issuer_name(x509));
5118}
5119
5120static jbyteArray NativeCrypto_X509_get_subject_name(JNIEnv* env, jclass, jlong x509Ref) {
5121    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5122    JNI_TRACE("X509_get_subject_name(%p)", x509);
5123    return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_subject_name(x509));
5124}
5125
5126static jstring NativeCrypto_get_X509_pubkey_oid(JNIEnv* env, jclass, jlong x509Ref) {
5127    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5128    JNI_TRACE("get_X509_pubkey_oid(%p)", x509);
5129
5130    if (x509 == NULL) {
5131        jniThrowNullPointerException(env, "x509 == null");
5132        JNI_TRACE("get_X509_pubkey_oid(%p) => x509 == null", x509);
5133        return NULL;
5134    }
5135
5136    X509_PUBKEY* pubkey = X509_get_X509_PUBKEY(x509);
5137    return ASN1_OBJECT_to_OID_string(env, pubkey->algor->algorithm);
5138}
5139
5140static jstring NativeCrypto_get_X509_sig_alg_oid(JNIEnv* env, jclass, jlong x509Ref) {
5141    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5142    JNI_TRACE("get_X509_sig_alg_oid(%p)", x509);
5143
5144    if (x509 == NULL || x509->sig_alg == NULL) {
5145        jniThrowNullPointerException(env, "x509 == NULL || x509->sig_alg == NULL");
5146        JNI_TRACE("get_X509_sig_alg_oid(%p) => x509 == NULL", x509);
5147        return NULL;
5148    }
5149
5150    return ASN1_OBJECT_to_OID_string(env, x509->sig_alg->algorithm);
5151}
5152
5153static jbyteArray NativeCrypto_get_X509_sig_alg_parameter(JNIEnv* env, jclass, jlong x509Ref) {
5154    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5155    JNI_TRACE("get_X509_sig_alg_parameter(%p)", x509);
5156
5157    if (x509 == NULL) {
5158        jniThrowNullPointerException(env, "x509 == null");
5159        JNI_TRACE("get_X509_sig_alg_parameter(%p) => x509 == null", x509);
5160        return NULL;
5161    }
5162
5163    if (x509->sig_alg->parameter == NULL) {
5164        JNI_TRACE("get_X509_sig_alg_parameter(%p) => null", x509);
5165        return NULL;
5166    }
5167
5168    return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, x509->sig_alg->parameter);
5169}
5170
5171static jbooleanArray NativeCrypto_get_X509_issuerUID(JNIEnv* env, jclass, jlong x509Ref) {
5172    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5173    JNI_TRACE("get_X509_issuerUID(%p)", x509);
5174
5175    if (x509 == NULL) {
5176        jniThrowNullPointerException(env, "x509 == null");
5177        JNI_TRACE("get_X509_issuerUID(%p) => x509 == null", x509);
5178        return NULL;
5179    }
5180
5181    if (x509->cert_info->issuerUID == NULL) {
5182        JNI_TRACE("get_X509_issuerUID(%p) => null", x509);
5183        return NULL;
5184    }
5185
5186    return ASN1BitStringToBooleanArray(env, x509->cert_info->issuerUID);
5187}
5188static jbooleanArray NativeCrypto_get_X509_subjectUID(JNIEnv* env, jclass, jlong x509Ref) {
5189    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5190    JNI_TRACE("get_X509_subjectUID(%p)", x509);
5191
5192    if (x509 == NULL) {
5193        jniThrowNullPointerException(env, "x509 == null");
5194        JNI_TRACE("get_X509_subjectUID(%p) => x509 == null", x509);
5195        return NULL;
5196    }
5197
5198    if (x509->cert_info->subjectUID == NULL) {
5199        JNI_TRACE("get_X509_subjectUID(%p) => null", x509);
5200        return NULL;
5201    }
5202
5203    return ASN1BitStringToBooleanArray(env, x509->cert_info->subjectUID);
5204}
5205
5206static jbooleanArray NativeCrypto_get_X509_ex_kusage(JNIEnv* env, jclass, jlong x509Ref) {
5207    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5208    JNI_TRACE("get_X509_ex_kusage(%p)", x509);
5209
5210    if (x509 == NULL) {
5211        jniThrowNullPointerException(env, "x509 == null");
5212        JNI_TRACE("get_X509_ex_kusage(%p) => x509 == null", x509);
5213        return NULL;
5214    }
5215
5216    Unique_ASN1_BIT_STRING bitStr(static_cast<ASN1_BIT_STRING*>(
5217            X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL)));
5218    if (bitStr.get() == NULL) {
5219        JNI_TRACE("get_X509_ex_kusage(%p) => null", x509);
5220        return NULL;
5221    }
5222
5223    return ASN1BitStringToBooleanArray(env, bitStr.get());
5224}
5225
5226static jobjectArray NativeCrypto_get_X509_ex_xkusage(JNIEnv* env, jclass, jlong x509Ref) {
5227    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5228    JNI_TRACE("get_X509_ex_xkusage(%p)", x509);
5229
5230    if (x509 == NULL) {
5231        jniThrowNullPointerException(env, "x509 == null");
5232        JNI_TRACE("get_X509_ex_xkusage(%p) => x509 == null", x509);
5233        return NULL;
5234    }
5235
5236    Unique_sk_ASN1_OBJECT objArray(static_cast<STACK_OF(ASN1_OBJECT)*>(
5237            X509_get_ext_d2i(x509, NID_ext_key_usage, NULL, NULL)));
5238    if (objArray.get() == NULL) {
5239        JNI_TRACE("get_X509_ex_xkusage(%p) => null", x509);
5240        return NULL;
5241    }
5242
5243    size_t size = sk_ASN1_OBJECT_num(objArray.get());
5244    ScopedLocalRef<jobjectArray> exKeyUsage(env, env->NewObjectArray(size, stringClass, NULL));
5245    if (exKeyUsage.get() == NULL) {
5246        return NULL;
5247    }
5248
5249    for (size_t i = 0; i < size; i++) {
5250        ScopedLocalRef<jstring> oidStr(env, ASN1_OBJECT_to_OID_string(env,
5251                sk_ASN1_OBJECT_value(objArray.get(), i)));
5252        env->SetObjectArrayElement(exKeyUsage.get(), i, oidStr.get());
5253    }
5254
5255    JNI_TRACE("get_X509_ex_xkusage(%p) => success (%d entries)", x509, size);
5256    return exKeyUsage.release();
5257}
5258
5259static jint NativeCrypto_get_X509_ex_pathlen(JNIEnv* env, jclass, jlong x509Ref) {
5260    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5261    JNI_TRACE("get_X509_ex_pathlen(%p)", x509);
5262
5263    if (x509 == NULL) {
5264        jniThrowNullPointerException(env, "x509 == null");
5265        JNI_TRACE("get_X509_ex_pathlen(%p) => x509 == null", x509);
5266        return 0;
5267    }
5268
5269    /* Just need to do this to cache the ex_* values. */
5270    X509_check_ca(x509);
5271
5272    JNI_TRACE("get_X509_ex_pathlen(%p) => %ld", x509, x509->ex_pathlen);
5273    return x509->ex_pathlen;
5274}
5275
5276static jbyteArray NativeCrypto_X509_get_ext_oid(JNIEnv* env, jclass, jlong x509Ref,
5277        jstring oidString) {
5278    X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
5279    JNI_TRACE("X509_get_ext_oid(%p, %p)", x509, oidString);
5280    return X509Type_get_ext_oid<X509, X509_get_ext_by_OBJ, X509_get_ext>(env, x509, oidString);
5281}
5282
5283static jbyteArray NativeCrypto_X509_CRL_get_ext_oid(JNIEnv* env, jclass, jlong x509CrlRef,
5284        jstring oidString) {
5285    X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
5286    JNI_TRACE("X509_CRL_get_ext_oid(%p, %p)", crl, oidString);
5287    return X509Type_get_ext_oid<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(env, crl,
5288            oidString);
5289}
5290
5291static jbyteArray NativeCrypto_X509_REVOKED_get_ext_oid(JNIEnv* env, jclass, jlong x509RevokedRef,
5292        jstring oidString) {
5293    X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
5294    JNI_TRACE("X509_REVOKED_get_ext_oid(%p, %p)", revoked, oidString);
5295    return X509Type_get_ext_oid<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, X509_REVOKED_get_ext>(
5296            env, revoked, oidString);
5297}
5298
5299template<typename T, int (*get_ext_by_critical_func)(T*, int, int), X509_EXTENSION* (*get_ext_func)(T*, int)>
5300static jobjectArray get_X509Type_ext_oids(JNIEnv* env, jlong x509Ref, jint critical) {
5301    T* x509 = reinterpret_cast<T*>(static_cast<uintptr_t>(x509Ref));
5302    JNI_TRACE("get_X509Type_ext_oids(%p, %d)", x509, critical);
5303
5304    if (x509 == NULL) {
5305        jniThrowNullPointerException(env, "x509 == null");
5306        JNI_TRACE("get_X509Type_ext_oids(%p, %d) => x509 == null", x509, critical);
5307        return NULL;
5308    }
5309
5310    int lastPos = -1;
5311    int count = 0;
5312    while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) {
5313        count++;
5314    }
5315
5316    JNI_TRACE("get_X509Type_ext_oids(%p, %d) has %d entries", x509, critical, count);
5317
5318    ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, stringClass, NULL));
5319    if (joa.get() == NULL) {
5320        JNI_TRACE("get_X509Type_ext_oids(%p, %d) => fail to allocate result array", x509, critical);
5321        return NULL;
5322    }
5323
5324    lastPos = -1;
5325    count = 0;
5326    while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) {
5327        X509_EXTENSION* ext = get_ext_func(x509, lastPos);
5328
5329        ScopedLocalRef<jstring> extOid(env, ASN1_OBJECT_to_OID_string(env, ext->object));
5330        if (extOid.get() == NULL) {
5331            JNI_TRACE("get_X509Type_ext_oids(%p) => couldn't get OID", x509);
5332            return NULL;
5333        }
5334
5335        env->SetObjectArrayElement(joa.get(), count++, extOid.get());
5336    }
5337
5338    JNI_TRACE("get_X509Type_ext_oids(%p, %d) => success", x509, critical);
5339    return joa.release();
5340}
5341
5342static jobjectArray NativeCrypto_get_X509_ext_oids(JNIEnv* env, jclass, jlong x509Ref,
5343        jint critical) {
5344    JNI_TRACE("get_X509_ext_oids(0x%llx, %d)", x509Ref, critical);
5345    return get_X509Type_ext_oids<X509, X509_get_ext_by_critical, X509_get_ext>(env, x509Ref,
5346            critical);
5347}
5348
5349static jobjectArray NativeCrypto_get_X509_CRL_ext_oids(JNIEnv* env, jclass, jlong x509CrlRef,
5350        jint critical) {
5351    JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509CrlRef, critical);
5352    return get_X509Type_ext_oids<X509_CRL, X509_CRL_get_ext_by_critical, X509_CRL_get_ext>(env,
5353            x509CrlRef, critical);
5354}
5355
5356static jobjectArray NativeCrypto_get_X509_REVOKED_ext_oids(JNIEnv* env, jclass, jlong x509RevokedRef,
5357        jint critical) {
5358    JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509RevokedRef, critical);
5359    return get_X509Type_ext_oids<X509_REVOKED, X509_REVOKED_get_ext_by_critical,
5360            X509_REVOKED_get_ext>(env, x509RevokedRef, critical);
5361}
5362
5363#ifdef WITH_JNI_TRACE
5364/**
5365 * Based on example logging call back from SSL_CTX_set_info_callback man page
5366 */
5367static void info_callback_LOG(const SSL* s __attribute__ ((unused)), int where, int ret)
5368{
5369    int w = where & ~SSL_ST_MASK;
5370    const char* str;
5371    if (w & SSL_ST_CONNECT) {
5372        str = "SSL_connect";
5373    } else if (w & SSL_ST_ACCEPT) {
5374        str = "SSL_accept";
5375    } else {
5376        str = "undefined";
5377    }
5378
5379    if (where & SSL_CB_LOOP) {
5380        JNI_TRACE("ssl=%p %s:%s %s", s, str, SSL_state_string(s), SSL_state_string_long(s));
5381    } else if (where & SSL_CB_ALERT) {
5382        str = (where & SSL_CB_READ) ? "read" : "write";
5383        JNI_TRACE("ssl=%p SSL3 alert %s:%s:%s %s %s",
5384                  s,
5385                  str,
5386                  SSL_alert_type_string(ret),
5387                  SSL_alert_desc_string(ret),
5388                  SSL_alert_type_string_long(ret),
5389                  SSL_alert_desc_string_long(ret));
5390    } else if (where & SSL_CB_EXIT) {
5391        if (ret == 0) {
5392            JNI_TRACE("ssl=%p %s:failed exit in %s %s",
5393                      s, str, SSL_state_string(s), SSL_state_string_long(s));
5394        } else if (ret < 0) {
5395            JNI_TRACE("ssl=%p %s:error exit in %s %s",
5396                      s, str, SSL_state_string(s), SSL_state_string_long(s));
5397        } else if (ret == 1) {
5398            JNI_TRACE("ssl=%p %s:ok exit in %s %s",
5399                      s, str, SSL_state_string(s), SSL_state_string_long(s));
5400        } else {
5401            JNI_TRACE("ssl=%p %s:unknown exit %d in %s %s",
5402                      s, str, ret, SSL_state_string(s), SSL_state_string_long(s));
5403        }
5404    } else if (where & SSL_CB_HANDSHAKE_START) {
5405        JNI_TRACE("ssl=%p handshake start in %s %s",
5406                  s, SSL_state_string(s), SSL_state_string_long(s));
5407    } else if (where & SSL_CB_HANDSHAKE_DONE) {
5408        JNI_TRACE("ssl=%p handshake done in %s %s",
5409                  s, SSL_state_string(s), SSL_state_string_long(s));
5410    } else {
5411        JNI_TRACE("ssl=%p %s:unknown where %d in %s %s",
5412                  s, str, where, SSL_state_string(s), SSL_state_string_long(s));
5413    }
5414}
5415#endif
5416
5417/**
5418 * Returns an array containing all the X509 certificate references
5419 */
5420static jlongArray getCertificateRefs(JNIEnv* env, const STACK_OF(X509)* chain)
5421{
5422    if (chain == NULL) {
5423        // Chain can be NULL if the associated cipher doesn't do certs.
5424        return NULL;
5425    }
5426    ssize_t count = sk_X509_num(chain);
5427    if (count <= 0) {
5428        return NULL;
5429    }
5430    ScopedLocalRef<jlongArray> refArray(env, env->NewLongArray(count));
5431    ScopedLongArrayRW refs(env, refArray.get());
5432    if (refs.get() == NULL) {
5433        return NULL;
5434    }
5435    for (ssize_t i = 0; i < count; i++) {
5436        refs[i] = reinterpret_cast<uintptr_t>(X509_dup_nocopy(sk_X509_value(chain, i)));
5437    }
5438    return refArray.release();
5439}
5440
5441/**
5442 * Returns an array containing all the X500 principal's bytes.
5443 */
5444static jobjectArray getPrincipalBytes(JNIEnv* env, const STACK_OF(X509_NAME)* names)
5445{
5446    if (names == NULL) {
5447        return NULL;
5448    }
5449
5450    int count = sk_X509_NAME_num(names);
5451    if (count <= 0) {
5452        return NULL;
5453    }
5454
5455    ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, byteArrayClass, NULL));
5456    if (joa.get() == NULL) {
5457        return NULL;
5458    }
5459
5460    for (int i = 0; i < count; i++) {
5461        X509_NAME* principal = sk_X509_NAME_value(names, i);
5462
5463        ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env,
5464                principal));
5465        if (byteArray.get() == NULL) {
5466            return NULL;
5467        }
5468        env->SetObjectArrayElement(joa.get(), i, byteArray.get());
5469    }
5470
5471    return joa.release();
5472}
5473
5474/**
5475 * Our additional application data needed for getting synchronization right.
5476 * This maybe warrants a bit of lengthy prose:
5477 *
5478 * (1) We use a flag to reflect whether we consider the SSL connection alive.
5479 * Any read or write attempt loops will be cancelled once this flag becomes 0.
5480 *
5481 * (2) We use an int to count the number of threads that are blocked by the
5482 * underlying socket. This may be at most two (one reader and one writer), since
5483 * the Java layer ensures that no more threads will enter the native code at the
5484 * same time.
5485 *
5486 * (3) The pipe is used primarily as a means of cancelling a blocking select()
5487 * when we want to close the connection (aka "emergency button"). It is also
5488 * necessary for dealing with a possible race condition situation: There might
5489 * be cases where both threads see an SSL_ERROR_WANT_READ or
5490 * SSL_ERROR_WANT_WRITE. Both will enter a select() with the proper argument.
5491 * If one leaves the select() successfully before the other enters it, the
5492 * "success" event is already consumed and the second thread will be blocked,
5493 * possibly forever (depending on network conditions).
5494 *
5495 * The idea for solving the problem looks like this: Whenever a thread is
5496 * successful in moving around data on the network, and it knows there is
5497 * another thread stuck in a select(), it will write a byte to the pipe, waking
5498 * up the other thread. A thread that returned from select(), on the other hand,
5499 * knows whether it's been woken up by the pipe. If so, it will consume the
5500 * byte, and the original state of affairs has been restored.
5501 *
5502 * The pipe may seem like a bit of overhead, but it fits in nicely with the
5503 * other file descriptors of the select(), so there's only one condition to wait
5504 * for.
5505 *
5506 * (4) Finally, a mutex is needed to make sure that at most one thread is in
5507 * either SSL_read() or SSL_write() at any given time. This is an OpenSSL
5508 * requirement. We use the same mutex to guard the field for counting the
5509 * waiting threads.
5510 *
5511 * Note: The current implementation assumes that we don't have to deal with
5512 * problems induced by multiple cores or processors and their respective
5513 * memory caches. One possible problem is that of inconsistent views on the
5514 * "aliveAndKicking" field. This could be worked around by also enclosing all
5515 * accesses to that field inside a lock/unlock sequence of our mutex, but
5516 * currently this seems a bit like overkill. Marking volatile at the very least.
5517 *
5518 * During handshaking, additional fields are used to up-call into
5519 * Java to perform certificate verification and handshake
5520 * completion. These are also used in any renegotiation.
5521 *
5522 * (5) the JNIEnv so we can invoke the Java callback
5523 *
5524 * (6) a NativeCrypto.SSLHandshakeCallbacks instance for callbacks from native to Java
5525 *
5526 * (7) a java.io.FileDescriptor wrapper to check for socket close
5527 *
5528 * We store the NPN protocols list so we can either send it (from the server) or
5529 * select a protocol (on the client). We eagerly acquire a pointer to the array
5530 * data so the callback doesn't need to acquire resources that it cannot
5531 * release.
5532 *
5533 * Because renegotiation can be requested by the peer at any time,
5534 * care should be taken to maintain an appropriate JNIEnv on any
5535 * downcall to openssl since it could result in an upcall to Java. The
5536 * current code does try to cover these cases by conditionally setting
5537 * the JNIEnv on calls that can read and write to the SSL such as
5538 * SSL_do_handshake, SSL_read, SSL_write, and SSL_shutdown.
5539 *
5540 * Finally, we have two emphemeral keys setup by OpenSSL callbacks:
5541 *
5542 * (8) a set of ephemeral RSA keys that is lazily generated if a peer
5543 * wants to use an exportable RSA cipher suite.
5544 *
5545 * (9) a set of ephemeral EC keys that is lazily generated if a peer
5546 * wants to use an TLS_ECDHE_* cipher suite.
5547 *
5548 */
5549class AppData {
5550  public:
5551    volatile int aliveAndKicking;
5552    int waitingThreads;
5553    int fdsEmergency[2];
5554    MUTEX_TYPE mutex;
5555    JNIEnv* env;
5556    jobject sslHandshakeCallbacks;
5557    jbyteArray npnProtocolsArray;
5558    jbyte* npnProtocolsData;
5559    size_t npnProtocolsLength;
5560    jbyteArray alpnProtocolsArray;
5561    jbyte* alpnProtocolsData;
5562    size_t alpnProtocolsLength;
5563    Unique_RSA ephemeralRsa;
5564    Unique_EC_KEY ephemeralEc;
5565
5566    /**
5567     * Creates the application data context for the SSL*.
5568     */
5569  public:
5570    static AppData* create() {
5571        UniquePtr<AppData> appData(new AppData());
5572        if (pipe(appData.get()->fdsEmergency) == -1) {
5573            ALOGE("AppData::create pipe(2) failed: %s", strerror(errno));
5574            return NULL;
5575        }
5576        if (!setBlocking(appData.get()->fdsEmergency[0], false)) {
5577            ALOGE("AppData::create fcntl(2) failed: %s", strerror(errno));
5578            return NULL;
5579        }
5580        if (MUTEX_SETUP(appData.get()->mutex) == -1) {
5581            ALOGE("pthread_mutex_init(3) failed: %s", strerror(errno));
5582            return NULL;
5583        }
5584        return appData.release();
5585    }
5586
5587    ~AppData() {
5588        aliveAndKicking = 0;
5589        if (fdsEmergency[0] != -1) {
5590            close(fdsEmergency[0]);
5591        }
5592        if (fdsEmergency[1] != -1) {
5593            close(fdsEmergency[1]);
5594        }
5595        MUTEX_CLEANUP(mutex);
5596    }
5597
5598  private:
5599    AppData() :
5600            aliveAndKicking(1),
5601            waitingThreads(0),
5602            env(NULL),
5603            sslHandshakeCallbacks(NULL),
5604            npnProtocolsArray(NULL),
5605            npnProtocolsData(NULL),
5606            npnProtocolsLength(-1),
5607            alpnProtocolsArray(NULL),
5608            alpnProtocolsData(NULL),
5609            alpnProtocolsLength(-1),
5610            ephemeralRsa(NULL),
5611            ephemeralEc(NULL) {
5612        fdsEmergency[0] = -1;
5613        fdsEmergency[1] = -1;
5614    }
5615
5616  public:
5617    /**
5618     * Used to set the SSL-to-Java callback state before each SSL_*
5619     * call that may result in a callback. It should be cleared after
5620     * the operation returns with clearCallbackState.
5621     *
5622     * @param env The JNIEnv
5623     * @param shc The SSLHandshakeCallbacks
5624     * @param fd The FileDescriptor
5625     * @param npnProtocols NPN protocols so that they may be advertised (by the
5626     *                     server) or selected (by the client). Has no effect
5627     *                     unless NPN is enabled.
5628     * @param alpnProtocols ALPN protocols so that they may be advertised (by the
5629     *                     server) or selected (by the client). Passing non-NULL
5630     *                     enables ALPN.
5631     */
5632    bool setCallbackState(JNIEnv* e, jobject shc, jobject fd, jbyteArray npnProtocols,
5633            jbyteArray alpnProtocols) {
5634        NetFd netFd(e, fd);
5635        if (netFd.isClosed()) {
5636            return false;
5637        }
5638        env = e;
5639        sslHandshakeCallbacks = shc;
5640        if (npnProtocols != NULL) {
5641            npnProtocolsArray = npnProtocols;
5642            npnProtocolsLength = e->GetArrayLength(npnProtocols);
5643            npnProtocolsData = e->GetByteArrayElements(npnProtocols, NULL);
5644            if (npnProtocolsData == NULL) {
5645                return false;
5646            }
5647        }
5648        if (alpnProtocols != NULL) {
5649            alpnProtocolsArray = alpnProtocols;
5650            alpnProtocolsLength = e->GetArrayLength(alpnProtocols);
5651            alpnProtocolsData = e->GetByteArrayElements(alpnProtocols, NULL);
5652            if (alpnProtocolsData == NULL) {
5653                return false;
5654            }
5655        }
5656        return true;
5657    }
5658
5659    void clearCallbackState() {
5660        sslHandshakeCallbacks = NULL;
5661        if (npnProtocolsArray != NULL) {
5662            env->ReleaseByteArrayElements(npnProtocolsArray, npnProtocolsData, JNI_ABORT);
5663            npnProtocolsArray = NULL;
5664            npnProtocolsData = NULL;
5665            npnProtocolsLength = -1;
5666        }
5667        if (alpnProtocolsArray != NULL) {
5668            env->ReleaseByteArrayElements(alpnProtocolsArray, alpnProtocolsData, JNI_ABORT);
5669            alpnProtocolsArray = NULL;
5670            alpnProtocolsData = NULL;
5671            alpnProtocolsLength = -1;
5672        }
5673        env = NULL;
5674    }
5675
5676};
5677
5678/**
5679 * Dark magic helper function that checks, for a given SSL session, whether it
5680 * can SSL_read() or SSL_write() without blocking. Takes into account any
5681 * concurrent attempts to close the SSLSocket from the Java side. This is
5682 * needed to get rid of the hangs that occur when thread #1 closes the SSLSocket
5683 * while thread #2 is sitting in a blocking read or write. The type argument
5684 * specifies whether we are waiting for readability or writability. It expects
5685 * to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we
5686 * only need to wait in case one of these problems occurs.
5687 *
5688 * @param env
5689 * @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
5690 * @param fdObject The FileDescriptor, since appData->fileDescriptor should be NULL
5691 * @param appData The application data structure with mutex info etc.
5692 * @param timeout_millis The timeout value for select call, with the special value
5693 *                0 meaning no timeout at all (wait indefinitely). Note: This is
5694 *                the Java semantics of the timeout value, not the usual
5695 *                select() semantics.
5696 * @return The result of the inner select() call,
5697 * THROW_SOCKETEXCEPTION if a SocketException was thrown, -1 on
5698 * additional errors
5699 */
5700static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout_millis) {
5701    // This loop is an expanded version of the NET_FAILURE_RETRY
5702    // macro. It cannot simply be used in this case because select
5703    // cannot be restarted without recreating the fd_sets and timeout
5704    // structure.
5705    int result;
5706    fd_set rfds;
5707    fd_set wfds;
5708    do {
5709        NetFd fd(env, fdObject);
5710        if (fd.isClosed()) {
5711            result = THROWN_EXCEPTION;
5712            break;
5713        }
5714        int intFd = fd.get();
5715        JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout_millis=%d",
5716                  (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout_millis);
5717
5718        FD_ZERO(&rfds);
5719        FD_ZERO(&wfds);
5720
5721        if (type == SSL_ERROR_WANT_READ) {
5722            FD_SET(intFd, &rfds);
5723        } else {
5724            FD_SET(intFd, &wfds);
5725        }
5726
5727        FD_SET(appData->fdsEmergency[0], &rfds);
5728
5729        int maxFd = (intFd > appData->fdsEmergency[0]) ? intFd : appData->fdsEmergency[0];
5730
5731        // Build a struct for the timeout data if we actually want a timeout.
5732        timeval tv;
5733        timeval* ptv;
5734        if (timeout_millis > 0) {
5735            tv.tv_sec = timeout_millis / 1000;
5736            tv.tv_usec = (timeout_millis % 1000) * 1000;
5737            ptv = &tv;
5738        } else {
5739            ptv = NULL;
5740        }
5741
5742        AsynchronousSocketCloseMonitor monitor(intFd);
5743        result = select(maxFd + 1, &rfds, &wfds, NULL, ptv);
5744        JNI_TRACE("sslSelect %s fd=%d appData=%p timeout_millis=%d => %d",
5745                  (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE",
5746                  fd.get(), appData, timeout_millis, result);
5747        if (result == -1) {
5748            if (fd.isClosed()) {
5749                result = THROWN_EXCEPTION;
5750                break;
5751            }
5752            if (errno != EINTR) {
5753                break;
5754            }
5755        }
5756    } while (result == -1);
5757
5758    if (MUTEX_LOCK(appData->mutex) == -1) {
5759        return -1;
5760    }
5761
5762    if (result > 0) {
5763        // We have been woken up by a token in the emergency pipe. We
5764        // can't be sure the token is still in the pipe at this point
5765        // because it could have already been read by the thread that
5766        // originally wrote it if it entered sslSelect and acquired
5767        // the mutex before we did. Thus we cannot safely read from
5768        // the pipe in a blocking way (so we make the pipe
5769        // non-blocking at creation).
5770        if (FD_ISSET(appData->fdsEmergency[0], &rfds)) {
5771            char token;
5772            do {
5773                read(appData->fdsEmergency[0], &token, 1);
5774            } while (errno == EINTR);
5775        }
5776    }
5777
5778    // Tell the world that there is now one thread less waiting for the
5779    // underlying network.
5780    appData->waitingThreads--;
5781
5782    MUTEX_UNLOCK(appData->mutex);
5783
5784    return result;
5785}
5786
5787/**
5788 * Helper function that wakes up a thread blocked in select(), in case there is
5789 * one. Is being called by sslRead() and sslWrite() as well as by JNI glue
5790 * before closing the connection.
5791 *
5792 * @param data The application data structure with mutex info etc.
5793 */
5794static void sslNotify(AppData* appData) {
5795    // Write a byte to the emergency pipe, so a concurrent select() can return.
5796    // Note we have to restore the errno of the original system call, since the
5797    // caller relies on it for generating error messages.
5798    int errnoBackup = errno;
5799    char token = '*';
5800    do {
5801        errno = 0;
5802        write(appData->fdsEmergency[1], &token, 1);
5803    } while (errno == EINTR);
5804    errno = errnoBackup;
5805}
5806
5807static AppData* toAppData(const SSL* ssl) {
5808    return reinterpret_cast<AppData*>(SSL_get_app_data(ssl));
5809}
5810
5811/**
5812 * Verify the X509 certificate via SSL_CTX_set_cert_verify_callback
5813 */
5814static int cert_verify_callback(X509_STORE_CTX* x509_store_ctx, void* arg __attribute__ ((unused)))
5815{
5816    /* Get the correct index to the SSLobject stored into X509_STORE_CTX. */
5817    SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(x509_store_ctx,
5818            SSL_get_ex_data_X509_STORE_CTX_idx()));
5819    JNI_TRACE("ssl=%p cert_verify_callback x509_store_ctx=%p arg=%p", ssl, x509_store_ctx, arg);
5820
5821    AppData* appData = toAppData(ssl);
5822    JNIEnv* env = appData->env;
5823    if (env == NULL) {
5824        ALOGE("AppData->env missing in cert_verify_callback");
5825        JNI_TRACE("ssl=%p cert_verify_callback => 0", ssl);
5826        return 0;
5827    }
5828    jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
5829
5830    jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
5831    jmethodID methodID
5832        = env->GetMethodID(cls, "verifyCertificateChain", "([JLjava/lang/String;)V");
5833
5834    jlongArray refArray = getCertificateRefs(env, x509_store_ctx->untrusted);
5835
5836    const char* authMethod = SSL_authentication_method(ssl);
5837    JNI_TRACE("ssl=%p cert_verify_callback calling verifyCertificateChain authMethod=%s",
5838              ssl, authMethod);
5839    jstring authMethodString = env->NewStringUTF(authMethod);
5840    env->CallVoidMethod(sslHandshakeCallbacks, methodID, refArray, authMethodString);
5841
5842    int result = (env->ExceptionCheck()) ? 0 : 1;
5843    JNI_TRACE("ssl=%p cert_verify_callback => %d", ssl, result);
5844    return result;
5845}
5846
5847/**
5848 * Call back to watch for handshake to be completed. This is necessary
5849 * for SSL_MODE_HANDSHAKE_CUTTHROUGH support, since SSL_do_handshake
5850 * returns before the handshake is completed in this case.
5851 */
5852static void info_callback(const SSL* ssl, int where, int ret __attribute__ ((unused))) {
5853    JNI_TRACE("ssl=%p info_callback where=0x%x ret=%d", ssl, where, ret);
5854#ifdef WITH_JNI_TRACE
5855    info_callback_LOG(ssl, where, ret);
5856#endif
5857    if (!(where & SSL_CB_HANDSHAKE_DONE)) {
5858        JNI_TRACE("ssl=%p info_callback ignored", ssl);
5859        return;
5860    }
5861
5862    AppData* appData = toAppData(ssl);
5863    JNIEnv* env = appData->env;
5864    if (env == NULL) {
5865        ALOGE("AppData->env missing in info_callback");
5866        JNI_TRACE("ssl=%p info_callback env error", ssl);
5867        return;
5868    }
5869    if (env->ExceptionCheck()) {
5870        JNI_TRACE("ssl=%p info_callback already pending exception", ssl);
5871        return;
5872    }
5873
5874    jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
5875
5876    jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
5877    jmethodID methodID = env->GetMethodID(cls, "handshakeCompleted", "()V");
5878
5879    JNI_TRACE("ssl=%p info_callback calling handshakeCompleted", ssl);
5880    env->CallVoidMethod(sslHandshakeCallbacks, methodID);
5881
5882    if (env->ExceptionCheck()) {
5883        JNI_TRACE("ssl=%p info_callback exception", ssl);
5884    }
5885    JNI_TRACE("ssl=%p info_callback completed", ssl);
5886}
5887
5888/**
5889 * Call back to ask for a client certificate. There are three possible exit codes:
5890 *
5891 * 1 is success. x509Out and pkeyOut should point to the correct private key and certificate.
5892 * 0 is unable to find key. x509Out and pkeyOut should be NULL.
5893 * -1 is error and it doesn't matter what x509Out and pkeyOut are.
5894 */
5895static int client_cert_cb(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) {
5896    JNI_TRACE("ssl=%p client_cert_cb x509Out=%p pkeyOut=%p", ssl, x509Out, pkeyOut);
5897
5898    /* Clear output of key and certificate in case of early exit due to error. */
5899    *x509Out = NULL;
5900    *pkeyOut = NULL;
5901
5902    AppData* appData = toAppData(ssl);
5903    JNIEnv* env = appData->env;
5904    if (env == NULL) {
5905        ALOGE("AppData->env missing in client_cert_cb");
5906        JNI_TRACE("ssl=%p client_cert_cb env error => 0", ssl);
5907        return 0;
5908    }
5909    if (env->ExceptionCheck()) {
5910        JNI_TRACE("ssl=%p client_cert_cb already pending exception => 0", ssl);
5911        return -1;
5912    }
5913    jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
5914
5915    jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
5916    jmethodID methodID
5917        = env->GetMethodID(cls, "clientCertificateRequested", "([B[[B)V");
5918
5919    // Call Java callback which can use SSL_use_certificate and SSL_use_PrivateKey to set values
5920    char ssl2_ctype = SSL3_CT_RSA_SIGN;
5921    const char* ctype = NULL;
5922    int ctype_num = 0;
5923    jobjectArray issuers = NULL;
5924    switch (ssl->version) {
5925        case SSL2_VERSION:
5926            ctype = &ssl2_ctype;
5927            ctype_num = 1;
5928            break;
5929        case SSL3_VERSION:
5930        case TLS1_VERSION:
5931        case TLS1_1_VERSION:
5932        case TLS1_2_VERSION:
5933        case DTLS1_VERSION:
5934            ctype = ssl->s3->tmp.ctype;
5935            ctype_num = ssl->s3->tmp.ctype_num;
5936            issuers = getPrincipalBytes(env, ssl->s3->tmp.ca_names);
5937            break;
5938    }
5939#ifdef WITH_JNI_TRACE
5940    for (int i = 0; i < ctype_num; i++) {
5941        JNI_TRACE("ssl=%p clientCertificateRequested keyTypes[%d]=%d", ssl, i, ctype[i]);
5942    }
5943#endif
5944
5945    jbyteArray keyTypes = env->NewByteArray(ctype_num);
5946    if (keyTypes == NULL) {
5947        JNI_TRACE("ssl=%p client_cert_cb bytes == null => 0", ssl);
5948        return 0;
5949    }
5950    env->SetByteArrayRegion(keyTypes, 0, ctype_num, reinterpret_cast<const jbyte*>(ctype));
5951
5952    JNI_TRACE("ssl=%p clientCertificateRequested calling clientCertificateRequested "
5953              "keyTypes=%p issuers=%p", ssl, keyTypes, issuers);
5954    env->CallVoidMethod(sslHandshakeCallbacks, methodID, keyTypes, issuers);
5955
5956    if (env->ExceptionCheck()) {
5957        JNI_TRACE("ssl=%p client_cert_cb exception => 0", ssl);
5958        return -1;
5959    }
5960
5961    // Check for values set from Java
5962    X509*     certificate = SSL_get_certificate(ssl);
5963    EVP_PKEY* privatekey  = SSL_get_privatekey(ssl);
5964    int result = 0;
5965    if (certificate != NULL && privatekey != NULL) {
5966        *x509Out = certificate;
5967        *pkeyOut = privatekey;
5968        result = 1;
5969    } else {
5970        // Some error conditions return NULL, so make sure it doesn't linger.
5971        freeOpenSslErrorState();
5972    }
5973    JNI_TRACE("ssl=%p client_cert_cb => *x509=%p *pkey=%p %d", ssl, *x509Out, *pkeyOut, result);
5974    return result;
5975}
5976
5977static RSA* rsaGenerateKey(int keylength) {
5978    Unique_BIGNUM bn(BN_new());
5979    if (bn.get() == NULL) {
5980        return NULL;
5981    }
5982    int setWordResult = BN_set_word(bn.get(), RSA_F4);
5983    if (setWordResult != 1) {
5984        return NULL;
5985    }
5986    Unique_RSA rsa(RSA_new());
5987    if (rsa.get() == NULL) {
5988        return NULL;
5989    }
5990    int generateResult = RSA_generate_key_ex(rsa.get(), keylength, bn.get(), NULL);
5991    if (generateResult != 1) {
5992        return NULL;
5993    }
5994    return rsa.release();
5995}
5996
5997/**
5998 * Call back to ask for an ephemeral RSA key for SSL_RSA_EXPORT_WITH_RC4_40_MD5 (aka EXP-RC4-MD5)
5999 */
6000static RSA* tmp_rsa_callback(SSL* ssl __attribute__ ((unused)),
6001                             int is_export __attribute__ ((unused)),
6002                             int keylength) {
6003    JNI_TRACE("ssl=%p tmp_rsa_callback is_export=%d keylength=%d", ssl, is_export, keylength);
6004
6005    AppData* appData = toAppData(ssl);
6006    if (appData->ephemeralRsa.get() == NULL) {
6007        JNI_TRACE("ssl=%p tmp_rsa_callback generating ephemeral RSA key", ssl);
6008        appData->ephemeralRsa.reset(rsaGenerateKey(keylength));
6009    }
6010    JNI_TRACE("ssl=%p tmp_rsa_callback => %p", ssl, appData->ephemeralRsa.get());
6011    return appData->ephemeralRsa.get();
6012}
6013
6014static DH* dhGenerateParameters(int keylength) {
6015
6016    /*
6017     * The SSL_CTX_set_tmp_dh_callback(3SSL) man page discusses two
6018     * different options for generating DH keys. One is generating the
6019     * keys using a single set of DH parameters. However, generating
6020     * DH parameters is slow enough (minutes) that they suggest doing
6021     * it once at install time. The other is to generate DH keys from
6022     * DSA parameters. Generating DSA parameters is faster than DH
6023     * parameters, but to prevent small subgroup attacks, they needed
6024     * to be regenerated for each set of DH keys. Setting the
6025     * SSL_OP_SINGLE_DH_USE option make sure OpenSSL will call back
6026     * for new DH parameters every type it needs to generate DH keys.
6027     */
6028#if 0
6029    // Slow path that takes minutes but could be cached
6030    Unique_DH dh(DH_new());
6031    if (!DH_generate_parameters_ex(dh.get(), keylength, 2, NULL)) {
6032        return NULL;
6033    }
6034    return dh.release();
6035#else
6036    // Faster path but must have SSL_OP_SINGLE_DH_USE set
6037    Unique_DSA dsa(DSA_new());
6038    if (!DSA_generate_parameters_ex(dsa.get(), keylength, NULL, 0, NULL, NULL, NULL)) {
6039        return NULL;
6040    }
6041    DH* dh = DSA_dup_DH(dsa.get());
6042    return dh;
6043#endif
6044}
6045
6046/**
6047 * Call back to ask for Diffie-Hellman parameters
6048 */
6049static DH* tmp_dh_callback(SSL* ssl __attribute__ ((unused)),
6050                           int is_export __attribute__ ((unused)),
6051                           int keylength) {
6052    JNI_TRACE("ssl=%p tmp_dh_callback is_export=%d keylength=%d", ssl, is_export, keylength);
6053    DH* tmp_dh = dhGenerateParameters(keylength);
6054    JNI_TRACE("ssl=%p tmp_dh_callback => %p", ssl, tmp_dh);
6055    return tmp_dh;
6056}
6057
6058static EC_KEY* ecGenerateKey(int keylength __attribute__ ((unused))) {
6059    // TODO selected curve based on keylength
6060    Unique_EC_KEY ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
6061    if (ec.get() == NULL) {
6062        return NULL;
6063    }
6064    return ec.release();
6065}
6066
6067/**
6068 * Call back to ask for an ephemeral EC key for TLS_ECDHE_* cipher suites
6069 */
6070static EC_KEY* tmp_ecdh_callback(SSL* ssl __attribute__ ((unused)),
6071                                 int is_export __attribute__ ((unused)),
6072                                 int keylength) {
6073    JNI_TRACE("ssl=%p tmp_ecdh_callback is_export=%d keylength=%d", ssl, is_export, keylength);
6074    AppData* appData = toAppData(ssl);
6075    if (appData->ephemeralEc.get() == NULL) {
6076        JNI_TRACE("ssl=%p tmp_ecdh_callback generating ephemeral EC key", ssl);
6077        appData->ephemeralEc.reset(ecGenerateKey(keylength));
6078    }
6079    JNI_TRACE("ssl=%p tmp_ecdh_callback => %p", ssl, appData->ephemeralEc.get());
6080    return appData->ephemeralEc.get();
6081}
6082
6083/*
6084 * public static native int SSL_CTX_new();
6085 */
6086static jlong NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) {
6087    Unique_SSL_CTX sslCtx(SSL_CTX_new(SSLv23_method()));
6088    if (sslCtx.get() == NULL) {
6089        throwExceptionIfNecessary(env, "SSL_CTX_new");
6090        return 0;
6091    }
6092    SSL_CTX_set_options(sslCtx.get(),
6093                        SSL_OP_ALL
6094                        // Note: We explicitly do not allow SSLv2 to be used.
6095                        | SSL_OP_NO_SSLv2
6096                        // We also disable session tickets for better compatibility b/2682876
6097                        | SSL_OP_NO_TICKET
6098                        // We also disable compression for better compatibility b/2710492 b/2710497
6099                        | SSL_OP_NO_COMPRESSION
6100                        // Because dhGenerateParameters uses DSA_generate_parameters_ex
6101                        | SSL_OP_SINGLE_DH_USE
6102                        // Because ecGenerateParameters uses a fixed named curve
6103                        | SSL_OP_SINGLE_ECDH_USE);
6104
6105    int mode = SSL_CTX_get_mode(sslCtx.get());
6106    /*
6107     * Turn on "partial write" mode. This means that SSL_write() will
6108     * behave like Posix write() and possibly return after only
6109     * writing a partial buffer. Note: The alternative, perhaps
6110     * surprisingly, is not that SSL_write() always does full writes
6111     * but that it will force you to retry write calls having
6112     * preserved the full state of the original call. (This is icky
6113     * and undesirable.)
6114     */
6115    mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
6116
6117    // Reuse empty buffers within the SSL_CTX to save memory
6118    mode |= SSL_MODE_RELEASE_BUFFERS;
6119
6120    SSL_CTX_set_mode(sslCtx.get(), mode);
6121
6122    SSL_CTX_set_cert_verify_callback(sslCtx.get(), cert_verify_callback, NULL);
6123    SSL_CTX_set_info_callback(sslCtx.get(), info_callback);
6124    SSL_CTX_set_client_cert_cb(sslCtx.get(), client_cert_cb);
6125    SSL_CTX_set_tmp_rsa_callback(sslCtx.get(), tmp_rsa_callback);
6126    SSL_CTX_set_tmp_dh_callback(sslCtx.get(), tmp_dh_callback);
6127    SSL_CTX_set_tmp_ecdh_callback(sslCtx.get(), tmp_ecdh_callback);
6128
6129    JNI_TRACE("NativeCrypto_SSL_CTX_new => %p", sslCtx.get());
6130    return (jlong) sslCtx.release();
6131}
6132
6133/**
6134 * public static native void SSL_CTX_free(int ssl_ctx)
6135 */
6136static void NativeCrypto_SSL_CTX_free(JNIEnv* env,
6137        jclass, jlong ssl_ctx_address)
6138{
6139    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6140    JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_free", ssl_ctx);
6141    if (ssl_ctx == NULL) {
6142        return;
6143    }
6144    SSL_CTX_free(ssl_ctx);
6145}
6146
6147static void NativeCrypto_SSL_CTX_set_session_id_context(JNIEnv* env, jclass,
6148                                                        jlong ssl_ctx_address, jbyteArray sid_ctx)
6149{
6150    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6151    JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context sid_ctx=%p", ssl_ctx, sid_ctx);
6152    if (ssl_ctx == NULL) {
6153        return;
6154    }
6155
6156    ScopedByteArrayRO buf(env, sid_ctx);
6157    if (buf.get() == NULL) {
6158        JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => threw exception", ssl_ctx);
6159        return;
6160    }
6161
6162    unsigned int length = buf.size();
6163    if (length > SSL_MAX_SSL_SESSION_ID_LENGTH) {
6164        jniThrowException(env, "java/lang/IllegalArgumentException",
6165                          "length > SSL_MAX_SSL_SESSION_ID_LENGTH");
6166        JNI_TRACE("NativeCrypto_SSL_CTX_set_session_id_context => length = %d", length);
6167        return;
6168    }
6169    const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buf.get());
6170    int result = SSL_CTX_set_session_id_context(ssl_ctx, bytes, length);
6171    if (result == 0) {
6172        throwExceptionIfNecessary(env, "NativeCrypto_SSL_CTX_set_session_id_context");
6173        return;
6174    }
6175    JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => ok", ssl_ctx);
6176}
6177
6178/**
6179 * public static native int SSL_new(int ssl_ctx) throws SSLException;
6180 */
6181static jlong NativeCrypto_SSL_new(JNIEnv* env, jclass, jlong ssl_ctx_address)
6182{
6183    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6184    JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new", ssl_ctx);
6185    if (ssl_ctx == NULL) {
6186        return 0;
6187    }
6188    Unique_SSL ssl(SSL_new(ssl_ctx));
6189    if (ssl.get() == NULL) {
6190        throwSSLExceptionWithSslErrors(env, NULL, SSL_ERROR_NONE,
6191                "Unable to create SSL structure");
6192        JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx);
6193        return 0;
6194    }
6195
6196    /* Java code in class OpenSSLSocketImpl does the verification. Meaning of
6197     * SSL_VERIFY_NONE flag in client mode: if not using an anonymous cipher
6198     * (by default disabled), the server will send a certificate which will
6199     * be checked. The result of the certificate verification process can be
6200     * checked after the TLS/SSL handshake using the SSL_get_verify_result(3)
6201     * function. The handshake will be continued regardless of the
6202     * verification result.
6203     */
6204    SSL_set_verify(ssl.get(), SSL_VERIFY_NONE, NULL);
6205
6206    JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => ssl=%p", ssl_ctx, ssl.get());
6207    return (jlong) ssl.release();
6208}
6209
6210
6211static void NativeCrypto_SSL_enable_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address)
6212{
6213    SSL* ssl = to_SSL(env, ssl_address, true);
6214    JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_enable_tls_channel_id", ssl);
6215    if (ssl == NULL) {
6216        return;
6217    }
6218
6219    long ret = SSL_enable_tls_channel_id(ssl);
6220    if (ret != 1L) {
6221        ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6222        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error enabling Channel ID");
6223        SSL_clear(ssl);
6224        JNI_TRACE("ssl=%p NativeCrypto_SSL_enable_tls_channel_id => error", ssl);
6225        return;
6226    }
6227}
6228
6229static jbyteArray NativeCrypto_SSL_get_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address)
6230{
6231    SSL* ssl = to_SSL(env, ssl_address, true);
6232    JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id", ssl);
6233    if (ssl == NULL) {
6234        return NULL;
6235    }
6236
6237    // Channel ID is 64 bytes long. Unfortunately, OpenSSL doesn't declare this length
6238    // as a constant anywhere.
6239    jbyteArray javaBytes = env->NewByteArray(64);
6240    ScopedByteArrayRW bytes(env, javaBytes);
6241    if (bytes.get() == NULL) {
6242        JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => NULL", ssl);
6243        return NULL;
6244    }
6245
6246    unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
6247    // Unfortunately, the SSL_get_tls_channel_id method below always returns 64 (upon success)
6248    // regardless of the number of bytes copied into the output buffer "tmp". Thus, the correctness
6249    // of this code currently relies on the "tmp" buffer being exactly 64 bytes long.
6250    long ret = SSL_get_tls_channel_id(ssl, tmp, 64);
6251    if (ret == 0) {
6252        // Channel ID either not set or did not verify
6253        JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => not available", ssl);
6254        return NULL;
6255    } else if (ret != 64) {
6256        ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6257        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error getting Channel ID");
6258        SSL_clear(ssl);
6259        JNI_TRACE("ssl=%p NativeCrypto_SSL_get_tls_channel_id => error, returned %ld", ssl, ret);
6260        return NULL;
6261    }
6262
6263    JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id() => %p", ssl, javaBytes);
6264    return javaBytes;
6265}
6266
6267static void NativeCrypto_SSL_set1_tls_channel_id(JNIEnv* env, jclass,
6268        jlong ssl_address, jlong pkeyRef)
6269{
6270    SSL* ssl = to_SSL(env, ssl_address, true);
6271    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
6272    JNI_TRACE("ssl=%p SSL_set1_tls_channel_id privatekey=%p", ssl, pkey);
6273    if (ssl == NULL) {
6274        return;
6275    }
6276
6277    if (pkey == NULL) {
6278        jniThrowNullPointerException(env, "pkey == null");
6279        JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => pkey == null", ssl);
6280        return;
6281    }
6282
6283    // SSL_set1_tls_channel_id requires ssl->server to be set to 0.
6284    // Unfortunately, the default value is 1 and it's only changed to 0 just
6285    // before the handshake starts (see NativeCrypto_SSL_do_handshake).
6286    ssl->server = 0;
6287    long ret = SSL_set1_tls_channel_id(ssl, pkey);
6288
6289    if (ret != 1L) {
6290        ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6291        throwSSLExceptionWithSslErrors(
6292                env, ssl, SSL_ERROR_NONE, "Error setting private key for Channel ID");
6293        SSL_clear(ssl);
6294        JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => error", ssl);
6295        return;
6296    }
6297    // SSL_set1_tls_channel_id expects to take ownership of the EVP_PKEY, but
6298    // we have an external reference from the caller such as an OpenSSLKey,
6299    // so we manually increment the reference count here.
6300    CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY);
6301
6302    JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => ok", ssl);
6303}
6304
6305static void NativeCrypto_SSL_use_PrivateKey(JNIEnv* env, jclass, jlong ssl_address, jlong pkeyRef) {
6306    SSL* ssl = to_SSL(env, ssl_address, true);
6307    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
6308    JNI_TRACE("ssl=%p SSL_use_PrivateKey privatekey=%p", ssl, pkey);
6309    if (ssl == NULL) {
6310        return;
6311    }
6312
6313    if (pkey == NULL) {
6314        jniThrowNullPointerException(env, "pkey == null");
6315        JNI_TRACE("ssl=%p SSL_use_PrivateKey => pkey == null", ssl);
6316        return;
6317    }
6318
6319    int ret = SSL_use_PrivateKey(ssl, pkey);
6320    if (ret != 1) {
6321        ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6322        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key");
6323        SSL_clear(ssl);
6324        JNI_TRACE("ssl=%p SSL_use_PrivateKey => error", ssl);
6325        return;
6326    }
6327    // SSL_use_PrivateKey expects to take ownership of the EVP_PKEY,
6328    // but we have an external reference from the caller such as an
6329    // OpenSSLKey, so we manually increment the reference count here.
6330    CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY);
6331
6332    JNI_TRACE("ssl=%p SSL_use_PrivateKey => ok", ssl);
6333}
6334
6335static void NativeCrypto_SSL_use_certificate(JNIEnv* env, jclass,
6336                                             jlong ssl_address, jlongArray certificatesJava)
6337{
6338    SSL* ssl = to_SSL(env, ssl_address, true);
6339    JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate certificates=%p", ssl, certificatesJava);
6340    if (ssl == NULL) {
6341        return;
6342    }
6343
6344    if (certificatesJava == NULL) {
6345        jniThrowNullPointerException(env, "certificates == null");
6346        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl);
6347        return;
6348    }
6349
6350    size_t length = env->GetArrayLength(certificatesJava);
6351    if (length == 0) {
6352        jniThrowException(env, "java/lang/IllegalArgumentException", "certificates.length == 0");
6353        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates.length == 0", ssl);
6354        return;
6355    }
6356
6357    ScopedLongArrayRO certificates(env, certificatesJava);
6358    if (certificates.get() == NULL) {
6359        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl);
6360        return;
6361    }
6362
6363    Unique_X509 serverCert(
6364            X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[0]))));
6365    if (serverCert.get() == NULL) {
6366        // Note this shouldn't happen since we checked the number of certificates above.
6367        jniThrowOutOfMemory(env, "Unable to allocate local certificate chain");
6368        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl);
6369        return;
6370    }
6371
6372    Unique_sk_X509 chain(sk_X509_new_null());
6373    if (chain.get() == NULL) {
6374        jniThrowOutOfMemory(env, "Unable to allocate local certificate chain");
6375        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl);
6376        return;
6377    }
6378
6379    for (size_t i = 1; i < length; i++) {
6380        Unique_X509 cert(
6381                X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[i]))));
6382        if (cert.get() == NULL || !sk_X509_push(chain.get(), cert.get())) {
6383            ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6384            throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate");
6385            SSL_clear(ssl);
6386            JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl);
6387            return;
6388        }
6389        OWNERSHIP_TRANSFERRED(cert);
6390    }
6391
6392    int ret = SSL_use_certificate(ssl, serverCert.get());
6393    if (ret != 1) {
6394        ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6395        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate");
6396        SSL_clear(ssl);
6397        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate error", ssl);
6398        return;
6399    }
6400    OWNERSHIP_TRANSFERRED(serverCert);
6401
6402    int chainResult = SSL_use_certificate_chain(ssl, chain.get());
6403    if (chainResult == 0) {
6404        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate chain");
6405        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate_chain error",
6406                  ssl);
6407        return;
6408    }
6409    OWNERSHIP_TRANSFERRED(chain);
6410
6411    JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => ok", ssl);
6412}
6413
6414static void NativeCrypto_SSL_check_private_key(JNIEnv* env, jclass, jlong ssl_address)
6415{
6416    SSL* ssl = to_SSL(env, ssl_address, true);
6417    JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key", ssl);
6418    if (ssl == NULL) {
6419        return;
6420    }
6421    int ret = SSL_check_private_key(ssl);
6422    if (ret != 1) {
6423        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error checking private key");
6424        SSL_clear(ssl);
6425        JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => error", ssl);
6426        return;
6427    }
6428    JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => ok", ssl);
6429}
6430
6431static void NativeCrypto_SSL_set_client_CA_list(JNIEnv* env, jclass,
6432                                                jlong ssl_address, jobjectArray principals)
6433{
6434    SSL* ssl = to_SSL(env, ssl_address, true);
6435    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list principals=%p", ssl, principals);
6436    if (ssl == NULL) {
6437        return;
6438    }
6439
6440    if (principals == NULL) {
6441        jniThrowNullPointerException(env, "principals == null");
6442        JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals == null", ssl);
6443        return;
6444    }
6445
6446    int length = env->GetArrayLength(principals);
6447    if (length == 0) {
6448        jniThrowException(env, "java/lang/IllegalArgumentException", "principals.length == 0");
6449        JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals.length == 0", ssl);
6450        return;
6451    }
6452
6453    Unique_sk_X509_NAME principalsStack(sk_X509_NAME_new_null());
6454    if (principalsStack.get() == NULL) {
6455        jniThrowOutOfMemory(env, "Unable to allocate principal stack");
6456        JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => stack allocation error", ssl);
6457        return;
6458    }
6459    for (int i = 0; i < length; i++) {
6460        ScopedLocalRef<jbyteArray> principal(env,
6461                reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(principals, i)));
6462        if (principal.get() == NULL) {
6463            jniThrowNullPointerException(env, "principals element == null");
6464            JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals element null", ssl);
6465            return;
6466        }
6467
6468        ScopedByteArrayRO buf(env, principal.get());
6469        if (buf.get() == NULL) {
6470            JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => threw exception", ssl);
6471            return;
6472        }
6473        const unsigned char* tmp = reinterpret_cast<const unsigned char*>(buf.get());
6474        Unique_X509_NAME principalX509Name(d2i_X509_NAME(NULL, &tmp, buf.size()));
6475
6476        if (principalX509Name.get() == NULL) {
6477            ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
6478            throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing principal");
6479            SSL_clear(ssl);
6480            JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals parsing error",
6481                      ssl);
6482            return;
6483        }
6484
6485        if (!sk_X509_NAME_push(principalsStack.get(), principalX509Name.release())) {
6486            jniThrowOutOfMemory(env, "Unable to push principal");
6487            JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principal push error", ssl);
6488            return;
6489        }
6490    }
6491
6492    SSL_set_client_CA_list(ssl, principalsStack.release());
6493    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => ok", ssl);
6494}
6495
6496/**
6497 * public static native long SSL_get_mode(int ssl);
6498 */
6499static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, jlong ssl_address) {
6500    SSL* ssl = to_SSL(env, ssl_address, true);
6501    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl);
6502    if (ssl == NULL) {
6503      return 0;
6504    }
6505    long mode = SSL_get_mode(ssl);
6506    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode);
6507    return mode;
6508}
6509
6510/**
6511 * public static native long SSL_set_mode(int ssl, long mode);
6512 */
6513static jlong NativeCrypto_SSL_set_mode(JNIEnv* env, jclass,
6514        jlong ssl_address, jlong mode) {
6515    SSL* ssl = to_SSL(env, ssl_address, true);
6516    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode mode=0x%llx", ssl, mode);
6517    if (ssl == NULL) {
6518      return 0;
6519    }
6520    long result = SSL_set_mode(ssl, mode);
6521    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode => 0x%lx", ssl, result);
6522    return result;
6523}
6524
6525/**
6526 * public static native long SSL_clear_mode(int ssl, long mode);
6527 */
6528static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass,
6529        jlong ssl_address, jlong mode) {
6530    SSL* ssl = to_SSL(env, ssl_address, true);
6531    JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, mode);
6532    if (ssl == NULL) {
6533      return 0;
6534    }
6535    long result = SSL_clear_mode(ssl, mode);
6536    JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result);
6537    return result;
6538}
6539
6540/**
6541 * public static native long SSL_get_options(int ssl);
6542 */
6543static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass,
6544        jlong ssl_address) {
6545    SSL* ssl = to_SSL(env, ssl_address, true);
6546    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl);
6547    if (ssl == NULL) {
6548      return 0;
6549    }
6550    long options = SSL_get_options(ssl);
6551    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options);
6552    return options;
6553}
6554
6555/**
6556 * public static native long SSL_set_options(int ssl, long options);
6557 */
6558static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass,
6559        jlong ssl_address, jlong options) {
6560    SSL* ssl = to_SSL(env, ssl_address, true);
6561    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options options=0x%llx", ssl, options);
6562    if (ssl == NULL) {
6563      return 0;
6564    }
6565    long result = SSL_set_options(ssl, options);
6566    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options => 0x%lx", ssl, result);
6567    return result;
6568}
6569
6570/**
6571 * public static native long SSL_clear_options(int ssl, long options);
6572 */
6573static jlong NativeCrypto_SSL_clear_options(JNIEnv* env, jclass,
6574        jlong ssl_address, jlong options) {
6575    SSL* ssl = to_SSL(env, ssl_address, true);
6576    JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options options=0x%llx", ssl, options);
6577    if (ssl == NULL) {
6578      return 0;
6579    }
6580    long result = SSL_clear_options(ssl, options);
6581    JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options => 0x%lx", ssl, result);
6582    return result;
6583}
6584
6585static jlongArray NativeCrypto_SSL_get_ciphers(JNIEnv* env, jclass, jlong ssl_address)
6586{
6587    SSL* ssl = to_SSL(env, ssl_address, true);
6588    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_ciphers", ssl);
6589
6590    STACK_OF(SSL_CIPHER)* cipherStack = SSL_get_ciphers(ssl);
6591    int count = (cipherStack != NULL) ? sk_SSL_CIPHER_num(cipherStack) : 0;
6592    ScopedLocalRef<jlongArray> ciphersArray(env, env->NewLongArray(count));
6593    ScopedLongArrayRW ciphers(env, ciphersArray.get());
6594    for (int i = 0; i < count; i++) {
6595        ciphers[i] = reinterpret_cast<jlong>(sk_SSL_CIPHER_value(cipherStack, i));
6596    }
6597
6598    JNI_TRACE("NativeCrypto_SSL_get_ciphers(%p) => %p [size=%d]", ssl, ciphersArray.get(), count);
6599    return ciphersArray.release();
6600}
6601
6602static jint NativeCrypto_get_SSL_CIPHER_algorithm_mkey(JNIEnv* env, jclass,
6603        jlong ssl_cipher_address)
6604{
6605    SSL_CIPHER* cipher = to_SSL_CIPHER(env, ssl_cipher_address, true);
6606    JNI_TRACE("cipher=%p get_SSL_CIPHER_algorithm_mkey => %ld", cipher, cipher->algorithm_mkey);
6607    return cipher->algorithm_mkey;
6608}
6609
6610static jint NativeCrypto_get_SSL_CIPHER_algorithm_auth(JNIEnv* env, jclass,
6611        jlong ssl_cipher_address)
6612{
6613    SSL_CIPHER* cipher = to_SSL_CIPHER(env, ssl_cipher_address, true);
6614    JNI_TRACE("cipher=%p get_SSL_CIPHER_algorithm_auth => %ld", cipher, cipher->algorithm_auth);
6615    return cipher->algorithm_auth;
6616}
6617
6618/**
6619 * Sets the ciphers suites that are enabled in the SSL
6620 */
6621static void NativeCrypto_SSL_set_cipher_lists(JNIEnv* env, jclass,
6622        jlong ssl_address, jobjectArray cipherSuites)
6623{
6624    SSL* ssl = to_SSL(env, ssl_address, true);
6625    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=%p", ssl, cipherSuites);
6626    if (ssl == NULL) {
6627        return;
6628    }
6629    if (cipherSuites == NULL) {
6630        jniThrowNullPointerException(env, "cipherSuites == null");
6631        return;
6632    }
6633
6634    Unique_sk_SSL_CIPHER cipherstack(sk_SSL_CIPHER_new_null());
6635    if (cipherstack.get() == NULL) {
6636        jniThrowRuntimeException(env, "sk_SSL_CIPHER_new_null failed");
6637        return;
6638    }
6639
6640    const SSL_METHOD* ssl_method = ssl->method;
6641    int num_ciphers = ssl_method->num_ciphers();
6642
6643    int length = env->GetArrayLength(cipherSuites);
6644    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists length=%d", ssl, length);
6645    for (int i = 0; i < length; i++) {
6646        ScopedLocalRef<jstring> cipherSuite(env,
6647                reinterpret_cast<jstring>(env->GetObjectArrayElement(cipherSuites, i)));
6648        ScopedUtfChars c(env, cipherSuite.get());
6649        if (c.c_str() == NULL) {
6650            return;
6651        }
6652        JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuite=%s", ssl, c.c_str());
6653        bool found = false;
6654        for (int j = 0; j < num_ciphers; j++) {
6655            const SSL_CIPHER* cipher = ssl_method->get_cipher(j);
6656            if ((strcmp(c.c_str(), cipher->name) == 0)
6657                    && (strcmp(SSL_CIPHER_get_version(cipher), "SSLv2"))) {
6658                if (!sk_SSL_CIPHER_push(cipherstack.get(), cipher)) {
6659                    jniThrowOutOfMemory(env, "Unable to push cipher");
6660                    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists => cipher push error", ssl);
6661                    return;
6662                }
6663                found = true;
6664            }
6665        }
6666        if (!found) {
6667            jniThrowException(env, "java/lang/IllegalArgumentException",
6668                              "Could not find cipher suite.");
6669            return;
6670        }
6671    }
6672
6673    int rc = SSL_set_cipher_lists(ssl, cipherstack.get());
6674    if (rc == 0) {
6675        freeOpenSslErrorState();
6676        jniThrowException(env, "java/lang/IllegalArgumentException",
6677                          "Illegal cipher suite strings.");
6678    } else {
6679        OWNERSHIP_TRANSFERRED(cipherstack);
6680    }
6681}
6682
6683/**
6684 * Sets certificate expectations, especially for server to request client auth
6685 */
6686static void NativeCrypto_SSL_set_verify(JNIEnv* env,
6687        jclass, jlong ssl_address, jint mode)
6688{
6689    SSL* ssl = to_SSL(env, ssl_address, true);
6690    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_verify mode=%x", ssl, mode);
6691    if (ssl == NULL) {
6692      return;
6693    }
6694    SSL_set_verify(ssl, (int)mode, NULL);
6695}
6696
6697/**
6698 * Sets the ciphers suites that are enabled in the SSL
6699 */
6700static void NativeCrypto_SSL_set_session(JNIEnv* env, jclass,
6701        jlong ssl_address, jlong ssl_session_address)
6702{
6703    SSL* ssl = to_SSL(env, ssl_address, true);
6704    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, false);
6705    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session ssl_session=%p", ssl, ssl_session);
6706    if (ssl == NULL) {
6707        return;
6708    }
6709
6710    int ret = SSL_set_session(ssl, ssl_session);
6711    if (ret != 1) {
6712        /*
6713         * Translate the error, and throw if it turns out to be a real
6714         * problem.
6715         */
6716        int sslErrorCode = SSL_get_error(ssl, ret);
6717        if (sslErrorCode != SSL_ERROR_ZERO_RETURN) {
6718            throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "SSL session set");
6719            SSL_clear(ssl);
6720        }
6721    }
6722}
6723
6724/**
6725 * Sets the ciphers suites that are enabled in the SSL
6726 */
6727static void NativeCrypto_SSL_set_session_creation_enabled(JNIEnv* env, jclass,
6728        jlong ssl_address, jboolean creation_enabled)
6729{
6730    SSL* ssl = to_SSL(env, ssl_address, true);
6731    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session_creation_enabled creation_enabled=%d",
6732              ssl, creation_enabled);
6733    if (ssl == NULL) {
6734        return;
6735    }
6736    SSL_set_session_creation_enabled(ssl, creation_enabled);
6737}
6738
6739static void NativeCrypto_SSL_set_tlsext_host_name(JNIEnv* env, jclass,
6740        jlong ssl_address, jstring hostname)
6741{
6742    SSL* ssl = to_SSL(env, ssl_address, true);
6743    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostname=%p",
6744              ssl, hostname);
6745    if (ssl == NULL) {
6746        return;
6747    }
6748
6749    ScopedUtfChars hostnameChars(env, hostname);
6750    if (hostnameChars.c_str() == NULL) {
6751        return;
6752    }
6753    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostnameChars=%s",
6754              ssl, hostnameChars.c_str());
6755
6756    int ret = SSL_set_tlsext_host_name(ssl, hostnameChars.c_str());
6757    if (ret != 1) {
6758        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting host name");
6759        SSL_clear(ssl);
6760        JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => error", ssl);
6761        return;
6762    }
6763    JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => ok", ssl);
6764}
6765
6766static jstring NativeCrypto_SSL_get_servername(JNIEnv* env, jclass, jlong ssl_address) {
6767    SSL* ssl = to_SSL(env, ssl_address, true);
6768    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername", ssl);
6769    if (ssl == NULL) {
6770        return NULL;
6771    }
6772    const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
6773    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername => %s", ssl, servername);
6774    return env->NewStringUTF(servername);
6775}
6776
6777/**
6778 * A common selection path for both NPN and ALPN since they're essentially the
6779 * same protocol. The list of protocols in "primary" is considered the order
6780 * which should take precedence.
6781 */
6782static int proto_select(SSL* ssl __attribute__ ((unused)),
6783        unsigned char **out, unsigned char *outLength,
6784        const unsigned char *primary, const unsigned int primaryLength,
6785        const unsigned char *secondary, const unsigned int secondaryLength) {
6786    if (primary != NULL) {
6787        JNI_TRACE("primary=%p, length=%d", primary, primaryLength);
6788
6789        int status = SSL_select_next_proto(out, outLength, primary, primaryLength, secondary,
6790                secondaryLength);
6791        switch (status) {
6792        case OPENSSL_NPN_NEGOTIATED:
6793            JNI_TRACE("ssl=%p proto_select NPN/ALPN negotiated", ssl);
6794            break;
6795        case OPENSSL_NPN_UNSUPPORTED:
6796            JNI_TRACE("ssl=%p proto_select NPN/ALPN unsupported", ssl);
6797            break;
6798        case OPENSSL_NPN_NO_OVERLAP:
6799            JNI_TRACE("ssl=%p proto_select NPN/ALPN no overlap", ssl);
6800            break;
6801        }
6802    } else {
6803        JNI_TRACE("protocols=NULL");
6804    }
6805    return SSL_TLSEXT_ERR_OK;
6806}
6807
6808/**
6809 * Callback for the server to select an ALPN protocol.
6810 */
6811static int alpn_select_callback(SSL* ssl, const unsigned char **out, unsigned char *outlen,
6812        const unsigned char *in, unsigned int inlen, void *) {
6813    JNI_TRACE("ssl=%p alpn_select_callback", ssl);
6814
6815    AppData* appData = toAppData(ssl);
6816    JNI_TRACE("AppData=%p", appData);
6817
6818    return proto_select(ssl, const_cast<unsigned char **>(out), outlen,
6819            reinterpret_cast<unsigned char*>(appData->alpnProtocolsData),
6820            appData->alpnProtocolsLength, in, inlen);
6821}
6822
6823/**
6824 * Callback for the client to select an NPN protocol.
6825 */
6826static int next_proto_select_callback(SSL* ssl, unsigned char** out, unsigned char* outlen,
6827                                      const unsigned char* in, unsigned int inlen, void*)
6828{
6829    JNI_TRACE("ssl=%p next_proto_select_callback", ssl);
6830
6831    AppData* appData = toAppData(ssl);
6832    JNI_TRACE("AppData=%p", appData);
6833
6834    // Enable False Start on the client if the server understands NPN
6835    // http://www.imperialviolet.org/2012/04/11/falsestart.html
6836    SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH);
6837
6838    return proto_select(ssl, out, outlen, in, inlen,
6839            reinterpret_cast<unsigned char*>(appData->npnProtocolsData),
6840            appData->npnProtocolsLength);
6841}
6842
6843/**
6844 * Callback for the server to advertise available protocols.
6845 */
6846static int next_protos_advertised_callback(SSL* ssl,
6847        const unsigned char **out, unsigned int *outlen, void *)
6848{
6849    JNI_TRACE("ssl=%p next_protos_advertised_callback", ssl);
6850    AppData* appData = toAppData(ssl);
6851    unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData);
6852    if (npnProtocols != NULL) {
6853        *out = npnProtocols;
6854        *outlen = appData->npnProtocolsLength;
6855    }
6856    return SSL_TLSEXT_ERR_OK;
6857}
6858
6859static void NativeCrypto_SSL_CTX_enable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address)
6860{
6861    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6862    if (ssl_ctx == NULL) {
6863        return;
6864    }
6865    SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); // client
6866    SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_protos_advertised_callback, NULL); // server
6867}
6868
6869static void NativeCrypto_SSL_CTX_disable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address)
6870{
6871    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6872    if (ssl_ctx == NULL) {
6873        return;
6874    }
6875    SSL_CTX_set_next_proto_select_cb(ssl_ctx, NULL, NULL); // client
6876    SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, NULL, NULL); // server
6877}
6878
6879static jbyteArray NativeCrypto_SSL_get_npn_negotiated_protocol(JNIEnv* env, jclass,
6880        jlong ssl_address)
6881{
6882    SSL* ssl = to_SSL(env, ssl_address, true);
6883    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_npn_negotiated_protocol", ssl);
6884    if (ssl == NULL) {
6885        return NULL;
6886    }
6887    const jbyte* npn;
6888    unsigned npnLength;
6889    SSL_get0_next_proto_negotiated(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength);
6890    if (npnLength == 0) {
6891        return NULL;
6892    }
6893    jbyteArray result = env->NewByteArray(npnLength);
6894    if (result != NULL) {
6895        env->SetByteArrayRegion(result, 0, npnLength, npn);
6896    }
6897    return result;
6898}
6899
6900static int NativeCrypto_SSL_CTX_set_alpn_protos(JNIEnv* env, jclass, jlong ssl_ctx_address,
6901        jbyteArray protos) {
6902    SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
6903    if (ssl_ctx == NULL) {
6904        return 0;
6905    }
6906
6907    JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p", ssl_ctx, protos);
6908
6909    if (protos == NULL) {
6910        JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=NULL", ssl_ctx);
6911        return 1;
6912    }
6913
6914    ScopedByteArrayRO protosBytes(env, protos);
6915    if (protosBytes.get() == NULL) {
6916        JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p => protosBytes == NULL", ssl_ctx,
6917                protos);
6918        return 0;
6919    }
6920
6921    const unsigned char *tmp = reinterpret_cast<const unsigned char*>(protosBytes.get());
6922    int ret = SSL_CTX_set_alpn_protos(ssl_ctx, tmp, protosBytes.size());
6923    JNI_TRACE("ssl_ctx=%p SSL_CTX_set_alpn_protos protos=%p => ret=%d", ssl_ctx, protos, ret);
6924    return ret;
6925}
6926
6927static jbyteArray NativeCrypto_SSL_get0_alpn_selected(JNIEnv* env, jclass,
6928        jlong ssl_address)
6929{
6930    SSL* ssl = to_SSL(env, ssl_address, true);
6931    JNI_TRACE("ssl=%p SSL_get0_alpn_selected", ssl);
6932    if (ssl == NULL) {
6933        return NULL;
6934    }
6935    const jbyte* npn;
6936    unsigned npnLength;
6937    SSL_get0_alpn_selected(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength);
6938    if (npnLength == 0) {
6939        return NULL;
6940    }
6941    jbyteArray result = env->NewByteArray(npnLength);
6942    if (result != NULL) {
6943        env->SetByteArrayRegion(result, 0, npnLength, npn);
6944    }
6945    return result;
6946}
6947
6948#ifdef WITH_JNI_TRACE_KEYS
6949static inline char hex_char(unsigned char in)
6950{
6951    if (in < 10) {
6952        return '0' + in;
6953    } else if (in <= 0xF0) {
6954        return 'A' + in - 10;
6955    } else {
6956        return '?';
6957    }
6958}
6959
6960static void hex_string(char **dest, unsigned char* input, int len)
6961{
6962    *dest = (char*) malloc(len * 2 + 1);
6963    char *output = *dest;
6964    for (int i = 0; i < len; i++) {
6965        *output++ = hex_char(input[i] >> 4);
6966        *output++ = hex_char(input[i] & 0xF);
6967    }
6968    *output = '\0';
6969}
6970
6971static void debug_print_session_key(SSL_SESSION* session)
6972{
6973    char *session_id_str;
6974    char *master_key_str;
6975    const char *key_type;
6976    char *keyline;
6977
6978    hex_string(&session_id_str, session->session_id, session->session_id_length);
6979    hex_string(&master_key_str, session->master_key, session->master_key_length);
6980
6981    X509* peer = SSL_SESSION_get0_peer(session);
6982    EVP_PKEY* pkey = X509_PUBKEY_get(peer->cert_info->key);
6983    switch (EVP_PKEY_type(pkey->type)) {
6984    case EVP_PKEY_RSA:
6985        key_type = "RSA";
6986        break;
6987    case EVP_PKEY_DSA:
6988        key_type = "DSA";
6989        break;
6990    case EVP_PKEY_EC:
6991        key_type = "EC";
6992        break;
6993    default:
6994        key_type = "Unknown";
6995        break;
6996    }
6997
6998    asprintf(&keyline, "%s Session-ID:%s Master-Key:%s\n", key_type, session_id_str,
6999            master_key_str);
7000    JNI_TRACE("ssl_session=%p %s", session, keyline);
7001
7002    free(session_id_str);
7003    free(master_key_str);
7004    free(keyline);
7005}
7006#endif /* WITH_JNI_TRACE_KEYS */
7007
7008/**
7009 * Perform SSL handshake
7010 */
7011static jlong NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject,
7012        jobject shc, jint timeout_millis, jboolean client_mode, jbyteArray npnProtocols,
7013        jbyteArray alpnProtocols) {
7014    SSL* ssl = to_SSL(env, ssl_address, true);
7015    JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd=%p shc=%p timeout_millis=%d client_mode=%d npn=%p",
7016              ssl, fdObject, shc, timeout_millis, client_mode, npnProtocols);
7017    if (ssl == NULL) {
7018        return 0;
7019    }
7020    if (fdObject == NULL) {
7021        jniThrowNullPointerException(env, "fd == null");
7022        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd == null => 0", ssl);
7023        return 0;
7024    }
7025    if (shc == NULL) {
7026        jniThrowNullPointerException(env, "sslHandshakeCallbacks == null");
7027        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslHandshakeCallbacks == null => 0", ssl);
7028        return 0;
7029    }
7030
7031    NetFd fd(env, fdObject);
7032    if (fd.isClosed()) {
7033        // SocketException thrown by NetFd.isClosed
7034        SSL_clear(ssl);
7035        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd.isClosed() => 0", ssl);
7036        return 0;
7037    }
7038
7039    int ret = SSL_set_fd(ssl, fd.get());
7040    JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake s=%d", ssl, fd.get());
7041
7042    if (ret != 1) {
7043        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE,
7044                                       "Error setting the file descriptor");
7045        SSL_clear(ssl);
7046        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake SSL_set_fd => 0", ssl);
7047        return 0;
7048    }
7049
7050    /*
7051     * Make socket non-blocking, so SSL_connect SSL_read() and SSL_write() don't hang
7052     * forever and we can use select() to find out if the socket is ready.
7053     */
7054    if (!setBlocking(fd.get(), false)) {
7055        throwSSLExceptionStr(env, "Unable to make socket non blocking");
7056        SSL_clear(ssl);
7057        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setBlocking => 0", ssl);
7058        return 0;
7059    }
7060
7061    /*
7062     * Create our special application data.
7063     */
7064    AppData* appData = AppData::create();
7065    if (appData == NULL) {
7066        throwSSLExceptionStr(env, "Unable to create application data");
7067        SSL_clear(ssl);
7068        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake appData => 0", ssl);
7069        return 0;
7070    }
7071
7072    SSL_set_app_data(ssl, reinterpret_cast<char*>(appData));
7073    JNI_TRACE("ssl=%p AppData::create => %p", ssl, appData);
7074
7075    if (client_mode) {
7076        SSL_set_connect_state(ssl);
7077    } else {
7078        SSL_set_accept_state(ssl);
7079        if (alpnProtocols != NULL) {
7080            SSL_CTX_set_alpn_select_cb(SSL_get_SSL_CTX(ssl), alpn_select_callback, NULL);
7081        }
7082    }
7083
7084    ret = 0;
7085    while (appData->aliveAndKicking) {
7086        errno = 0;
7087
7088        if (!appData->setCallbackState(env, shc, fdObject, npnProtocols, alpnProtocols)) {
7089            // SocketException thrown by NetFd.isClosed
7090            SSL_clear(ssl);
7091            JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setCallbackState => 0", ssl);
7092            return 0;
7093        }
7094        ret = SSL_do_handshake(ssl);
7095        appData->clearCallbackState();
7096        // cert_verify_callback threw exception
7097        if (env->ExceptionCheck()) {
7098            SSL_clear(ssl);
7099            JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake exception => 0", ssl);
7100            return 0;
7101        }
7102        // success case
7103        if (ret == 1) {
7104            break;
7105        }
7106        // retry case
7107        if (errno == EINTR) {
7108            continue;
7109        }
7110        // error case
7111        int sslError = SSL_get_error(ssl, ret);
7112        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake ret=%d errno=%d sslError=%d timeout_millis=%d",
7113                  ssl, ret, errno, sslError, timeout_millis);
7114
7115        /*
7116         * If SSL_do_handshake doesn't succeed due to the socket being
7117         * either unreadable or unwritable, we use sslSelect to
7118         * wait for it to become ready. If that doesn't happen
7119         * before the specified timeout or an error occurs, we
7120         * cancel the handshake. Otherwise we try the SSL_connect
7121         * again.
7122         */
7123        if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) {
7124            appData->waitingThreads++;
7125            int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis);
7126
7127            if (selectResult == THROWN_EXCEPTION) {
7128                // SocketException thrown by NetFd.isClosed
7129                SSL_clear(ssl);
7130                JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslSelect => 0", ssl);
7131                return 0;
7132            }
7133            if (selectResult == -1) {
7134                throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_SYSCALL, "handshake error");
7135                SSL_clear(ssl);
7136                JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == -1 => 0", ssl);
7137                return 0;
7138            }
7139            if (selectResult == 0) {
7140                throwSocketTimeoutException(env, "SSL handshake timed out");
7141                SSL_clear(ssl);
7142                freeOpenSslErrorState();
7143                JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == 0 => 0", ssl);
7144                return 0;
7145            }
7146        } else {
7147            // ALOGE("Unknown error %d during handshake", error);
7148            break;
7149        }
7150    }
7151
7152    // clean error. See SSL_do_handshake(3SSL) man page.
7153    if (ret == 0) {
7154        /*
7155         * The other side closed the socket before the handshake could be
7156         * completed, but everything is within the bounds of the TLS protocol.
7157         * We still might want to find out the real reason of the failure.
7158         */
7159        int sslError = SSL_get_error(ssl, ret);
7160        if (sslError == SSL_ERROR_NONE || (sslError == SSL_ERROR_SYSCALL && errno == 0)) {
7161            throwSSLExceptionStr(env, "Connection closed by peer");
7162        } else {
7163            throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL handshake terminated");
7164        }
7165        SSL_clear(ssl);
7166        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake clean error => 0", ssl);
7167        return 0;
7168    }
7169
7170    // unclean error. See SSL_do_handshake(3SSL) man page.
7171    if (ret < 0) {
7172        /*
7173         * Translate the error and throw exception. We are sure it is an error
7174         * at this point.
7175         */
7176        int sslError = SSL_get_error(ssl, ret);
7177        throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL handshake aborted");
7178        SSL_clear(ssl);
7179        JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake unclean error => 0", ssl);
7180        return 0;
7181    }
7182    SSL_SESSION* ssl_session = SSL_get1_session(ssl);
7183    JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => ssl_session=%p", ssl, ssl_session);
7184#ifdef WITH_JNI_TRACE_KEYS
7185    debug_print_session_key(ssl_session);
7186#endif
7187    return (jlong) ssl_session;
7188}
7189
7190/**
7191 * Perform SSL renegotiation
7192 */
7193static void NativeCrypto_SSL_renegotiate(JNIEnv* env, jclass, jlong ssl_address)
7194{
7195    SSL* ssl = to_SSL(env, ssl_address, true);
7196    JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate", ssl);
7197    if (ssl == NULL) {
7198        return;
7199    }
7200    int result = SSL_renegotiate(ssl);
7201    if (result != 1) {
7202        throwSSLExceptionStr(env, "Problem with SSL_renegotiate");
7203        return;
7204    }
7205    // first call asks client to perform renegotiation
7206    int ret = SSL_do_handshake(ssl);
7207    if (ret != 1) {
7208        int sslError = SSL_get_error(ssl, ret);
7209        throwSSLExceptionWithSslErrors(env, ssl, sslError,
7210                                       "Problem with SSL_do_handshake after SSL_renegotiate");
7211        return;
7212    }
7213    // if client agrees, set ssl state and perform renegotiation
7214    ssl->state = SSL_ST_ACCEPT;
7215    SSL_do_handshake(ssl);
7216    JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate =>", ssl);
7217}
7218
7219/**
7220 * public static native byte[][] SSL_get_certificate(int ssl);
7221 */
7222static jlongArray NativeCrypto_SSL_get_certificate(JNIEnv* env, jclass, jlong ssl_address)
7223{
7224    SSL* ssl = to_SSL(env, ssl_address, true);
7225    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate", ssl);
7226    if (ssl == NULL) {
7227        return NULL;
7228    }
7229    X509* certificate = SSL_get_certificate(ssl);
7230    if (certificate == NULL) {
7231        JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
7232        // SSL_get_certificate can return NULL during an error as well.
7233        freeOpenSslErrorState();
7234        return NULL;
7235    }
7236
7237    Unique_sk_X509 chain(sk_X509_new_null());
7238    if (chain.get() == NULL) {
7239        jniThrowOutOfMemory(env, "Unable to allocate local certificate chain");
7240        JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => threw exception", ssl);
7241        return NULL;
7242    }
7243    if (!sk_X509_push(chain.get(), X509_dup_nocopy(certificate))) {
7244        jniThrowOutOfMemory(env, "Unable to push local certificate");
7245        JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
7246        return NULL;
7247    }
7248    STACK_OF(X509)* cert_chain = SSL_get_certificate_chain(ssl, certificate);
7249    for (int i=0; i<sk_X509_num(cert_chain); i++) {
7250        if (!sk_X509_push(chain.get(), X509_dup_nocopy(sk_X509_value(cert_chain, i)))) {
7251            jniThrowOutOfMemory(env, "Unable to push local certificate chain");
7252            JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
7253            return NULL;
7254        }
7255    }
7256
7257    jlongArray refArray = getCertificateRefs(env, chain.get());
7258    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => %p", ssl, refArray);
7259    return refArray;
7260}
7261
7262// Fills a long[] with the peer certificates in the chain.
7263static jlongArray NativeCrypto_SSL_get_peer_cert_chain(JNIEnv* env, jclass, jlong ssl_address)
7264{
7265    SSL* ssl = to_SSL(env, ssl_address, true);
7266    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain", ssl);
7267    if (ssl == NULL) {
7268        return NULL;
7269    }
7270    STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
7271    Unique_sk_X509 chain_copy(NULL);
7272    if (ssl->server) {
7273        X509* x509 = SSL_get_peer_certificate(ssl);
7274        if (x509 == NULL) {
7275            JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => NULL", ssl);
7276            return NULL;
7277        }
7278        chain_copy.reset(sk_X509_new_null());
7279        if (chain_copy.get() == NULL) {
7280            jniThrowOutOfMemory(env, "Unable to allocate peer certificate chain");
7281            JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate dup error", ssl);
7282            return NULL;
7283        }
7284        size_t chain_size = sk_X509_num(chain);
7285        for (size_t i = 0; i < chain_size; i++) {
7286            if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(sk_X509_value(chain, i)))) {
7287                jniThrowOutOfMemory(env, "Unable to push server's peer certificate chain");
7288                JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate chain push error", ssl);
7289                return NULL;
7290            }
7291        }
7292        if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(x509))) {
7293            jniThrowOutOfMemory(env, "Unable to push server's peer certificate");
7294            JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate push error", ssl);
7295            return NULL;
7296        }
7297        chain = chain_copy.get();
7298    }
7299    jlongArray refArray = getCertificateRefs(env, chain);
7300    JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => %p", ssl, refArray);
7301    return refArray;
7302}
7303
7304/**
7305 * Helper function which does the actual reading. The Java layer guarantees that
7306 * at most one thread will enter this function at any given time.
7307 *
7308 * @param ssl non-null; the SSL context
7309 * @param buf non-null; buffer to read into
7310 * @param len length of the buffer, in bytes
7311 * @param sslReturnCode original SSL return code
7312 * @param sslErrorCode filled in with the SSL error code in case of error
7313 * @return number of bytes read on success, -1 if the connection was
7314 * cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
7315 */
7316static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len,
7317                   int* sslReturnCode, int* sslErrorCode, int read_timeout_millis) {
7318    JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len);
7319
7320    if (len == 0) {
7321        // Don't bother doing anything in this case.
7322        return 0;
7323    }
7324
7325    BIO* bio = SSL_get_rbio(ssl);
7326
7327    AppData* appData = toAppData(ssl);
7328    if (appData == NULL) {
7329        return THROW_SSLEXCEPTION;
7330    }
7331
7332    while (appData->aliveAndKicking) {
7333        errno = 0;
7334
7335        if (MUTEX_LOCK(appData->mutex) == -1) {
7336            return -1;
7337        }
7338
7339        unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
7340
7341        if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) {
7342            MUTEX_UNLOCK(appData->mutex);
7343            return THROWN_EXCEPTION;
7344        }
7345        int result = SSL_read(ssl, buf, len);
7346        appData->clearCallbackState();
7347        // callbacks can happen if server requests renegotiation
7348        if (env->ExceptionCheck()) {
7349            SSL_clear(ssl);
7350            JNI_TRACE("ssl=%p sslRead => THROWN_EXCEPTION", ssl);
7351            return THROWN_EXCEPTION;
7352        }
7353        int sslError = SSL_ERROR_NONE;
7354        if (result <= 0) {
7355            sslError = SSL_get_error(ssl, result);
7356            freeOpenSslErrorState();
7357        }
7358        JNI_TRACE("ssl=%p sslRead SSL_read result=%d sslError=%d", ssl, result, sslError);
7359#ifdef WITH_JNI_TRACE_DATA
7360        for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) {
7361            int n = result - i;
7362            if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) {
7363                n = WITH_JNI_TRACE_DATA_CHUNK_SIZE;
7364            }
7365            JNI_TRACE("ssl=%p sslRead data: %d:\n%.*s", ssl, n, n, buf+i);
7366        }
7367#endif
7368
7369        // If we have been successful in moving data around, check whether it
7370        // might make sense to wake up other blocked threads, so they can give
7371        // it a try, too.
7372        if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved
7373                && appData->waitingThreads > 0) {
7374            sslNotify(appData);
7375        }
7376
7377        // If we are blocked by the underlying socket, tell the world that
7378        // there will be one more waiting thread now.
7379        if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) {
7380            appData->waitingThreads++;
7381        }
7382
7383        MUTEX_UNLOCK(appData->mutex);
7384
7385        switch (sslError) {
7386            // Successfully read at least one byte.
7387            case SSL_ERROR_NONE: {
7388                return result;
7389            }
7390
7391            // Read zero bytes. End of stream reached.
7392            case SSL_ERROR_ZERO_RETURN: {
7393                return -1;
7394            }
7395
7396            // Need to wait for availability of underlying layer, then retry.
7397            case SSL_ERROR_WANT_READ:
7398            case SSL_ERROR_WANT_WRITE: {
7399                int selectResult = sslSelect(env, sslError, fdObject, appData, read_timeout_millis);
7400                if (selectResult == THROWN_EXCEPTION) {
7401                    return THROWN_EXCEPTION;
7402                }
7403                if (selectResult == -1) {
7404                    *sslReturnCode = -1;
7405                    *sslErrorCode = sslError;
7406                    return THROW_SSLEXCEPTION;
7407                }
7408                if (selectResult == 0) {
7409                    return THROW_SOCKETTIMEOUTEXCEPTION;
7410                }
7411
7412                break;
7413            }
7414
7415            // A problem occurred during a system call, but this is not
7416            // necessarily an error.
7417            case SSL_ERROR_SYSCALL: {
7418                // Connection closed without proper shutdown. Tell caller we
7419                // have reached end-of-stream.
7420                if (result == 0) {
7421                    return -1;
7422                }
7423
7424                // System call has been interrupted. Simply retry.
7425                if (errno == EINTR) {
7426                    break;
7427                }
7428
7429                // Note that for all other system call errors we fall through
7430                // to the default case, which results in an Exception.
7431            }
7432
7433            // Everything else is basically an error.
7434            default: {
7435                *sslReturnCode = result;
7436                *sslErrorCode = sslError;
7437                return THROW_SSLEXCEPTION;
7438            }
7439        }
7440    }
7441
7442    return -1;
7443}
7444
7445/**
7446 * OpenSSL read function (2): read into buffer at offset n chunks.
7447 * Returns 1 (success) or value <= 0 (failure).
7448 */
7449static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject,
7450                                  jobject shc, jbyteArray b, jint offset, jint len,
7451                                  jint read_timeout_millis)
7452{
7453    SSL* ssl = to_SSL(env, ssl_address, true);
7454    JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d read_timeout_millis=%d",
7455              ssl, fdObject, shc, b, offset, len, read_timeout_millis);
7456    if (ssl == NULL) {
7457        return 0;
7458    }
7459    if (fdObject == NULL) {
7460        jniThrowNullPointerException(env, "fd == null");
7461        JNI_TRACE("ssl=%p NativeCrypto_SSL_read => fd == null", ssl);
7462        return 0;
7463    }
7464    if (shc == NULL) {
7465        jniThrowNullPointerException(env, "sslHandshakeCallbacks == null");
7466        JNI_TRACE("ssl=%p NativeCrypto_SSL_read => sslHandshakeCallbacks == null", ssl);
7467        return 0;
7468    }
7469
7470    ScopedByteArrayRW bytes(env, b);
7471    if (bytes.get() == NULL) {
7472        JNI_TRACE("ssl=%p NativeCrypto_SSL_read => threw exception", ssl);
7473        return 0;
7474    }
7475    int returnCode = 0;
7476    int sslErrorCode = SSL_ERROR_NONE;;
7477
7478    int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len,
7479                      &returnCode, &sslErrorCode, read_timeout_millis);
7480
7481    int result;
7482    switch (ret) {
7483        case THROW_SSLEXCEPTION:
7484            // See sslRead() regarding improper failure to handle normal cases.
7485            throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Read error");
7486            result = -1;
7487            break;
7488        case THROW_SOCKETTIMEOUTEXCEPTION:
7489            throwSocketTimeoutException(env, "Read timed out");
7490            result = -1;
7491            break;
7492        case THROWN_EXCEPTION:
7493            // SocketException thrown by NetFd.isClosed
7494            // or RuntimeException thrown by callback
7495            result = -1;
7496            break;
7497        default:
7498            result = ret;
7499            break;
7500    }
7501
7502    JNI_TRACE("ssl=%p NativeCrypto_SSL_read => %d", ssl, result);
7503    return result;
7504}
7505
7506/**
7507 * Helper function which does the actual writing. The Java layer guarantees that
7508 * at most one thread will enter this function at any given time.
7509 *
7510 * @param ssl non-null; the SSL context
7511 * @param buf non-null; buffer to write
7512 * @param len length of the buffer, in bytes
7513 * @param sslReturnCode original SSL return code
7514 * @param sslErrorCode filled in with the SSL error code in case of error
7515 * @return number of bytes read on success, -1 if the connection was
7516 * cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
7517 */
7518static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const char* buf, jint len,
7519                    int* sslReturnCode, int* sslErrorCode, int write_timeout_millis) {
7520    JNI_TRACE("ssl=%p sslWrite buf=%p len=%d write_timeout_millis=%d",
7521              ssl, buf, len, write_timeout_millis);
7522
7523    if (len == 0) {
7524        // Don't bother doing anything in this case.
7525        return 0;
7526    }
7527
7528    BIO* bio = SSL_get_wbio(ssl);
7529
7530    AppData* appData = toAppData(ssl);
7531    if (appData == NULL) {
7532        return THROW_SSLEXCEPTION;
7533    }
7534
7535    int count = len;
7536
7537    while (appData->aliveAndKicking && ((len > 0) || (ssl->s3->wbuf.left > 0))) {
7538        errno = 0;
7539
7540        if (MUTEX_LOCK(appData->mutex) == -1) {
7541            return -1;
7542        }
7543
7544        unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
7545
7546        if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) {
7547            MUTEX_UNLOCK(appData->mutex);
7548            return THROWN_EXCEPTION;
7549        }
7550        JNI_TRACE("ssl=%p sslWrite SSL_write len=%d left=%d", ssl, len, ssl->s3->wbuf.left);
7551        int result = SSL_write(ssl, buf, len);
7552        appData->clearCallbackState();
7553        // callbacks can happen if server requests renegotiation
7554        if (env->ExceptionCheck()) {
7555            SSL_clear(ssl);
7556            JNI_TRACE("ssl=%p sslWrite exception => THROWN_EXCEPTION", ssl);
7557            return THROWN_EXCEPTION;
7558        }
7559        int sslError = SSL_ERROR_NONE;
7560        if (result <= 0) {
7561            sslError = SSL_get_error(ssl, result);
7562            freeOpenSslErrorState();
7563        }
7564        JNI_TRACE("ssl=%p sslWrite SSL_write result=%d sslError=%d left=%d",
7565                  ssl, result, sslError, ssl->s3->wbuf.left);
7566#ifdef WITH_JNI_TRACE_DATA
7567        for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) {
7568            int n = result - i;
7569            if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) {
7570                n = WITH_JNI_TRACE_DATA_CHUNK_SIZE;
7571            }
7572            JNI_TRACE("ssl=%p sslWrite data: %d:\n%.*s", ssl, n, n, buf+i);
7573        }
7574#endif
7575
7576        // If we have been successful in moving data around, check whether it
7577        // might make sense to wake up other blocked threads, so they can give
7578        // it a try, too.
7579        if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved
7580                && appData->waitingThreads > 0) {
7581            sslNotify(appData);
7582        }
7583
7584        // If we are blocked by the underlying socket, tell the world that
7585        // there will be one more waiting thread now.
7586        if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) {
7587            appData->waitingThreads++;
7588        }
7589
7590        MUTEX_UNLOCK(appData->mutex);
7591
7592        switch (sslError) {
7593            // Successfully wrote at least one byte.
7594            case SSL_ERROR_NONE: {
7595                buf += result;
7596                len -= result;
7597                break;
7598            }
7599
7600            // Wrote zero bytes. End of stream reached.
7601            case SSL_ERROR_ZERO_RETURN: {
7602                return -1;
7603            }
7604
7605            // Need to wait for availability of underlying layer, then retry.
7606            // The concept of a write timeout doesn't really make sense, and
7607            // it's also not standard Java behavior, so we wait forever here.
7608            case SSL_ERROR_WANT_READ:
7609            case SSL_ERROR_WANT_WRITE: {
7610                int selectResult = sslSelect(env, sslError, fdObject, appData, write_timeout_millis);
7611                if (selectResult == THROWN_EXCEPTION) {
7612                    return THROWN_EXCEPTION;
7613                }
7614                if (selectResult == -1) {
7615                    *sslReturnCode = -1;
7616                    *sslErrorCode = sslError;
7617                    return THROW_SSLEXCEPTION;
7618                }
7619                if (selectResult == 0) {
7620                    return THROW_SOCKETTIMEOUTEXCEPTION;
7621                }
7622
7623                break;
7624            }
7625
7626            // A problem occurred during a system call, but this is not
7627            // necessarily an error.
7628            case SSL_ERROR_SYSCALL: {
7629                // Connection closed without proper shutdown. Tell caller we
7630                // have reached end-of-stream.
7631                if (result == 0) {
7632                    return -1;
7633                }
7634
7635                // System call has been interrupted. Simply retry.
7636                if (errno == EINTR) {
7637                    break;
7638                }
7639
7640                // Note that for all other system call errors we fall through
7641                // to the default case, which results in an Exception.
7642            }
7643
7644            // Everything else is basically an error.
7645            default: {
7646                *sslReturnCode = result;
7647                *sslErrorCode = sslError;
7648                return THROW_SSLEXCEPTION;
7649            }
7650        }
7651    }
7652    JNI_TRACE("ssl=%p sslWrite => count=%d", ssl, count);
7653
7654    return count;
7655}
7656
7657/**
7658 * OpenSSL write function (2): write into buffer at offset n chunks.
7659 */
7660static void NativeCrypto_SSL_write(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject,
7661                                   jobject shc, jbyteArray b, jint offset, jint len, jint write_timeout_millis)
7662{
7663    SSL* ssl = to_SSL(env, ssl_address, true);
7664    JNI_TRACE("ssl=%p NativeCrypto_SSL_write fd=%p shc=%p b=%p offset=%d len=%d write_timeout_millis=%d",
7665              ssl, fdObject, shc, b, offset, len, write_timeout_millis);
7666    if (ssl == NULL) {
7667        return;
7668    }
7669    if (fdObject == NULL) {
7670        jniThrowNullPointerException(env, "fd == null");
7671        JNI_TRACE("ssl=%p NativeCrypto_SSL_write => fd == null", ssl);
7672        return;
7673    }
7674    if (shc == NULL) {
7675        jniThrowNullPointerException(env, "sslHandshakeCallbacks == null");
7676        JNI_TRACE("ssl=%p NativeCrypto_SSL_write => sslHandshakeCallbacks == null", ssl);
7677        return;
7678    }
7679
7680    ScopedByteArrayRO bytes(env, b);
7681    if (bytes.get() == NULL) {
7682        JNI_TRACE("ssl=%p NativeCrypto_SSL_write => threw exception", ssl);
7683        return;
7684    }
7685    int returnCode = 0;
7686    int sslErrorCode = SSL_ERROR_NONE;
7687    int ret = sslWrite(env, ssl, fdObject, shc, reinterpret_cast<const char*>(bytes.get() + offset),
7688                       len, &returnCode, &sslErrorCode, write_timeout_millis);
7689
7690    switch (ret) {
7691        case THROW_SSLEXCEPTION:
7692            // See sslWrite() regarding improper failure to handle normal cases.
7693            throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Write error");
7694            break;
7695        case THROW_SOCKETTIMEOUTEXCEPTION:
7696            throwSocketTimeoutException(env, "Write timed out");
7697            break;
7698        case THROWN_EXCEPTION:
7699            // SocketException thrown by NetFd.isClosed
7700            break;
7701        default:
7702            break;
7703    }
7704}
7705
7706/**
7707 * Interrupt any pending I/O before closing the socket.
7708 */
7709static void NativeCrypto_SSL_interrupt(
7710        JNIEnv* env, jclass, jlong ssl_address) {
7711    SSL* ssl = to_SSL(env, ssl_address, false);
7712    JNI_TRACE("ssl=%p NativeCrypto_SSL_interrupt", ssl);
7713    if (ssl == NULL) {
7714        return;
7715    }
7716
7717    /*
7718     * Mark the connection as quasi-dead, then send something to the emergency
7719     * file descriptor, so any blocking select() calls are woken up.
7720     */
7721    AppData* appData = toAppData(ssl);
7722    if (appData != NULL) {
7723        appData->aliveAndKicking = 0;
7724
7725        // At most two threads can be waiting.
7726        sslNotify(appData);
7727        sslNotify(appData);
7728    }
7729}
7730
7731/**
7732 * OpenSSL close SSL socket function.
7733 */
7734static void NativeCrypto_SSL_shutdown(JNIEnv* env, jclass, jlong ssl_address,
7735                                      jobject fdObject, jobject shc) {
7736    SSL* ssl = to_SSL(env, ssl_address, false);
7737    JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown fd=%p shc=%p", ssl, fdObject, shc);
7738    if (ssl == NULL) {
7739        return;
7740    }
7741    if (fdObject == NULL) {
7742        jniThrowNullPointerException(env, "fd == null");
7743        JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => fd == null", ssl);
7744        return;
7745    }
7746    if (shc == NULL) {
7747        jniThrowNullPointerException(env, "sslHandshakeCallbacks == null");
7748        JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => sslHandshakeCallbacks == null", ssl);
7749        return;
7750    }
7751
7752    AppData* appData = toAppData(ssl);
7753    if (appData != NULL) {
7754        if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) {
7755            // SocketException thrown by NetFd.isClosed
7756            SSL_clear(ssl);
7757            freeOpenSslErrorState();
7758            return;
7759        }
7760
7761        /*
7762         * Try to make socket blocking again. OpenSSL literature recommends this.
7763         */
7764        int fd = SSL_get_fd(ssl);
7765        JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown s=%d", ssl, fd);
7766        if (fd != -1) {
7767            setBlocking(fd, true);
7768        }
7769
7770        int ret = SSL_shutdown(ssl);
7771        appData->clearCallbackState();
7772        // callbacks can happen if server requests renegotiation
7773        if (env->ExceptionCheck()) {
7774            SSL_clear(ssl);
7775            JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => exception", ssl);
7776            return;
7777        }
7778        switch (ret) {
7779            case 0:
7780                /*
7781                 * Shutdown was not successful (yet), but there also
7782                 * is no error. Since we can't know whether the remote
7783                 * server is actually still there, and we don't want to
7784                 * get stuck forever in a second SSL_shutdown() call, we
7785                 * simply return. This is not security a problem as long
7786                 * as we close the underlying socket, which we actually
7787                 * do, because that's where we are just coming from.
7788                 */
7789                break;
7790            case 1:
7791                /*
7792                 * Shutdown was successful. We can safely return. Hooray!
7793                 */
7794                break;
7795            default:
7796                /*
7797                 * Everything else is a real error condition. We should
7798                 * let the Java layer know about this by throwing an
7799                 * exception.
7800                 */
7801                int sslError = SSL_get_error(ssl, ret);
7802                throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL shutdown failed");
7803                break;
7804        }
7805    }
7806
7807    SSL_clear(ssl);
7808    freeOpenSslErrorState();
7809}
7810
7811/**
7812 * public static native void SSL_free(int ssl);
7813 */
7814static void NativeCrypto_SSL_free(JNIEnv* env, jclass, jlong ssl_address)
7815{
7816    SSL* ssl = to_SSL(env, ssl_address, true);
7817    JNI_TRACE("ssl=%p NativeCrypto_SSL_free", ssl);
7818    if (ssl == NULL) {
7819        return;
7820    }
7821
7822    AppData* appData = toAppData(ssl);
7823    SSL_set_app_data(ssl, NULL);
7824    delete appData;
7825    SSL_free(ssl);
7826}
7827
7828/**
7829 * Gets and returns in a byte array the ID of the actual SSL session.
7830 */
7831static jbyteArray NativeCrypto_SSL_SESSION_session_id(JNIEnv* env, jclass,
7832                                                      jlong ssl_session_address) {
7833    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7834    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id", ssl_session);
7835    if (ssl_session == NULL) {
7836        return NULL;
7837    }
7838    jbyteArray result = env->NewByteArray(ssl_session->session_id_length);
7839    if (result != NULL) {
7840        jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id);
7841        env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src);
7842    }
7843    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id => %p session_id_length=%d",
7844             ssl_session, result, ssl_session->session_id_length);
7845    return result;
7846}
7847
7848/**
7849 * Gets and returns in a long integer the creation's time of the
7850 * actual SSL session.
7851 */
7852static jlong NativeCrypto_SSL_SESSION_get_time(JNIEnv* env, jclass, jlong ssl_session_address) {
7853    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7854    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time", ssl_session);
7855    if (ssl_session == NULL) {
7856        return 0;
7857    }
7858    // result must be jlong, not long or *1000 will overflow
7859    jlong result = SSL_SESSION_get_time(ssl_session);
7860    result *= 1000; // OpenSSL uses seconds, Java uses milliseconds.
7861    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time => %lld", ssl_session, result);
7862    return result;
7863}
7864
7865/**
7866 * Gets and returns in a string the version of the SSL protocol. If it
7867 * returns the string "unknown" it means that no connection is established.
7868 */
7869static jstring NativeCrypto_SSL_SESSION_get_version(JNIEnv* env, jclass, jlong ssl_session_address) {
7870    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7871    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version", ssl_session);
7872    if (ssl_session == NULL) {
7873        return NULL;
7874    }
7875    const char* protocol = SSL_SESSION_get_version(ssl_session);
7876    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version => %s", ssl_session, protocol);
7877    return env->NewStringUTF(protocol);
7878}
7879
7880/**
7881 * Gets and returns in a string the cipher negotiated for the SSL session.
7882 */
7883static jstring NativeCrypto_SSL_SESSION_cipher(JNIEnv* env, jclass, jlong ssl_session_address) {
7884    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7885    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher", ssl_session);
7886    if (ssl_session == NULL) {
7887        return NULL;
7888    }
7889    const SSL_CIPHER* cipher = ssl_session->cipher;
7890    const char* name = SSL_CIPHER_get_name(cipher);
7891    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher => %s", ssl_session, name);
7892    return env->NewStringUTF(name);
7893}
7894
7895/**
7896 * Frees the SSL session.
7897 */
7898static void NativeCrypto_SSL_SESSION_free(JNIEnv* env, jclass, jlong ssl_session_address) {
7899    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7900    JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_free", ssl_session);
7901    if (ssl_session == NULL) {
7902        return;
7903    }
7904    SSL_SESSION_free(ssl_session);
7905}
7906
7907
7908/**
7909 * Serializes the native state of the session (ID, cipher, and keys but
7910 * not certificates). Returns a byte[] containing the DER-encoded state.
7911 * See apache mod_ssl.
7912 */
7913static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jlong ssl_session_address) {
7914    SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
7915    JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION", ssl_session);
7916    if (ssl_session == NULL) {
7917        return NULL;
7918    }
7919    return ASN1ToByteArray<SSL_SESSION, i2d_SSL_SESSION>(env, ssl_session);
7920}
7921
7922/**
7923 * Deserialize the session.
7924 */
7925static jlong NativeCrypto_d2i_SSL_SESSION(JNIEnv* env, jclass, jbyteArray javaBytes) {
7926    JNI_TRACE("NativeCrypto_d2i_SSL_SESSION bytes=%p", javaBytes);
7927
7928    ScopedByteArrayRO bytes(env, javaBytes);
7929    if (bytes.get() == NULL) {
7930        JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => threw exception");
7931        return 0;
7932    }
7933    const unsigned char* ucp = reinterpret_cast<const unsigned char*>(bytes.get());
7934    SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, bytes.size());
7935
7936    // Initialize SSL_SESSION cipher field based on cipher_id http://b/7091840
7937    if (ssl_session != NULL) {
7938        // based on ssl_get_prev_session
7939        uint32_t cipher_id_network_order = htonl(ssl_session->cipher_id);
7940        uint8_t* cipher_id_byte_pointer = reinterpret_cast<uint8_t*>(&cipher_id_network_order);
7941        if (ssl_session->ssl_version >= SSL3_VERSION_MAJOR) {
7942            cipher_id_byte_pointer += 2; // skip first two bytes for SSL3+
7943        } else {
7944            cipher_id_byte_pointer += 1; // skip first byte for SSL2
7945        }
7946        ssl_session->cipher = SSLv23_method()->get_cipher_by_char(cipher_id_byte_pointer);
7947        JNI_TRACE("NativeCrypto_d2i_SSL_SESSION cipher_id=%lx hton=%x 0=%x 1=%x cipher=%s",
7948                  ssl_session->cipher_id, cipher_id_network_order,
7949                  cipher_id_byte_pointer[0], cipher_id_byte_pointer[1],
7950                  SSL_CIPHER_get_name(ssl_session->cipher));
7951    } else {
7952        freeOpenSslErrorState();
7953    }
7954
7955    JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => %p", ssl_session);
7956    return reinterpret_cast<uintptr_t>(ssl_session);
7957}
7958
7959static jlong NativeCrypto_ERR_peek_last_error(JNIEnv*, jclass) {
7960    return ERR_peek_last_error();
7961}
7962
7963#define FILE_DESCRIPTOR "Ljava/io/FileDescriptor;"
7964#define SSL_CALLBACKS "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto$SSLHandshakeCallbacks;"
7965static JNINativeMethod sNativeCryptoMethods[] = {
7966    NATIVE_METHOD(NativeCrypto, clinit, "()V"),
7967    NATIVE_METHOD(NativeCrypto, ENGINE_load_dynamic, "()V"),
7968    NATIVE_METHOD(NativeCrypto, ENGINE_by_id, "(Ljava/lang/String;)J"),
7969    NATIVE_METHOD(NativeCrypto, ENGINE_add, "(J)I"),
7970    NATIVE_METHOD(NativeCrypto, ENGINE_init, "(J)I"),
7971    NATIVE_METHOD(NativeCrypto, ENGINE_finish, "(J)I"),
7972    NATIVE_METHOD(NativeCrypto, ENGINE_free, "(J)I"),
7973    NATIVE_METHOD(NativeCrypto, ENGINE_load_private_key, "(JLjava/lang/String;)J"),
7974    NATIVE_METHOD(NativeCrypto, ENGINE_get_id, "(J)Ljava/lang/String;"),
7975    NATIVE_METHOD(NativeCrypto, ENGINE_ctrl_cmd_string, "(JLjava/lang/String;Ljava/lang/String;I)I"),
7976    NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_DSA, "([B[B[B[B[B)J"),
7977    NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)J"),
7978    NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_EC_KEY, "(JJ[B)J"),
7979    NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_mac_key, "(I[B)J"),
7980    NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(J)I"),
7981    NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(J)I"),
7982    NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_public, "(J)Ljava/lang/String;"),
7983    NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_private, "(J)Ljava/lang/String;"),
7984    NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(J)V"),
7985    NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(JJ)I"),
7986    NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(J)[B"),
7987    NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)J"),
7988    NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(J)[B"),
7989    NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)J"),
7990    NATIVE_METHOD(NativeCrypto, RSA_generate_key_ex, "(I[B)J"),
7991    NATIVE_METHOD(NativeCrypto, RSA_size, "(J)I"),
7992    NATIVE_METHOD(NativeCrypto, RSA_private_encrypt, "(I[B[BJI)I"),
7993    NATIVE_METHOD(NativeCrypto, RSA_public_decrypt, "(I[B[BJI)I"),
7994    NATIVE_METHOD(NativeCrypto, RSA_public_encrypt, "(I[B[BJI)I"),
7995    NATIVE_METHOD(NativeCrypto, RSA_private_decrypt, "(I[B[BJI)I"),
7996    NATIVE_METHOD(NativeCrypto, get_RSA_private_params, "(J)[[B"),
7997    NATIVE_METHOD(NativeCrypto, get_RSA_public_params, "(J)[[B"),
7998    NATIVE_METHOD(NativeCrypto, DSA_generate_key, "(I[B[B[B[B)J"),
7999    NATIVE_METHOD(NativeCrypto, get_DSA_params, "(J)[[B"),
8000    NATIVE_METHOD(NativeCrypto, EC_GROUP_new_by_curve_name, "(Ljava/lang/String;)J"),
8001    NATIVE_METHOD(NativeCrypto, EC_GROUP_new_curve, "(I[B[B[B)J"),
8002    NATIVE_METHOD(NativeCrypto, EC_GROUP_dup, "(J)J"),
8003    NATIVE_METHOD(NativeCrypto, EC_GROUP_set_asn1_flag, "(JI)V"),
8004    NATIVE_METHOD(NativeCrypto, EC_GROUP_set_point_conversion_form, "(JI)V"),
8005    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve_name, "(J)Ljava/lang/String;"),
8006    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve, "(J)[[B"),
8007    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_order, "(J)[B"),
8008    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_degree, "(J)I"),
8009    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_cofactor, "(J)[B"),
8010    NATIVE_METHOD(NativeCrypto, EC_GROUP_clear_free, "(J)V"),
8011    NATIVE_METHOD(NativeCrypto, EC_GROUP_cmp, "(JJ)Z"),
8012    NATIVE_METHOD(NativeCrypto, EC_GROUP_get_generator, "(J)J"),
8013    NATIVE_METHOD(NativeCrypto, EC_GROUP_set_generator, "(JJ[B[B)V"),
8014    NATIVE_METHOD(NativeCrypto, get_EC_GROUP_type, "(J)I"),
8015    NATIVE_METHOD(NativeCrypto, EC_POINT_new, "(J)J"),
8016    NATIVE_METHOD(NativeCrypto, EC_POINT_clear_free, "(J)V"),
8017    NATIVE_METHOD(NativeCrypto, EC_POINT_cmp, "(JJJ)Z"),
8018    NATIVE_METHOD(NativeCrypto, EC_POINT_set_affine_coordinates, "(JJ[B[B)V"),
8019    NATIVE_METHOD(NativeCrypto, EC_POINT_get_affine_coordinates, "(JJ)[[B"),
8020    NATIVE_METHOD(NativeCrypto, EC_KEY_generate_key, "(J)J"),
8021    NATIVE_METHOD(NativeCrypto, EC_KEY_get0_group, "(J)J"),
8022    NATIVE_METHOD(NativeCrypto, EC_KEY_get_private_key, "(J)[B"),
8023    NATIVE_METHOD(NativeCrypto, EC_KEY_get_public_key, "(J)J"),
8024    NATIVE_METHOD(NativeCrypto, ECDH_compute_key, "([BIJJ)I"),
8025    NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_create, "()J"),
8026    NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_init, "(J)V"),
8027    NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_destroy, "(J)V"),
8028    NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_copy, "(J)J"),
8029    NATIVE_METHOD(NativeCrypto, EVP_DigestFinal, "(J[BI)I"),
8030    NATIVE_METHOD(NativeCrypto, EVP_DigestInit, "(J)J"),
8031    NATIVE_METHOD(NativeCrypto, EVP_get_digestbyname, "(Ljava/lang/String;)J"),
8032    NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(J)I"),
8033    NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(J)I"),
8034    NATIVE_METHOD(NativeCrypto, EVP_DigestUpdate, "(J[BII)V"),
8035    NATIVE_METHOD(NativeCrypto, EVP_SignInit, "(Ljava/lang/String;)J"),
8036    NATIVE_METHOD(NativeCrypto, EVP_SignUpdate, "(J[BII)V"),
8037    NATIVE_METHOD(NativeCrypto, EVP_SignFinal, "(J[BIJ)I"),
8038    NATIVE_METHOD(NativeCrypto, EVP_VerifyInit, "(Ljava/lang/String;)J"),
8039    NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdate, "(J[BII)V"),
8040    NATIVE_METHOD(NativeCrypto, EVP_VerifyFinal, "(J[BIIJ)I"),
8041    NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(JJJ)V"),
8042    NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(J[B)V"),
8043    NATIVE_METHOD(NativeCrypto, EVP_DigestSignFinal, "(J)[B"),
8044    NATIVE_METHOD(NativeCrypto, EVP_get_cipherbyname, "(Ljava/lang/String;)J"),
8045    NATIVE_METHOD(NativeCrypto, EVP_CipherInit_ex, "(JJ[B[BZ)V"),
8046    NATIVE_METHOD(NativeCrypto, EVP_CipherUpdate, "(J[BI[BII)I"),
8047    NATIVE_METHOD(NativeCrypto, EVP_CipherFinal_ex, "(J[BI)I"),
8048    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_iv_length, "(J)I"),
8049    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_new, "()J"),
8050    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_block_size, "(J)I"),
8051    NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_buf_len, "(J)I"),
8052    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_padding, "(JZ)V"),
8053    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_key_length, "(JI)V"),
8054    NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_cleanup, "(J)V"),
8055    NATIVE_METHOD(NativeCrypto, RAND_seed, "([B)V"),
8056    NATIVE_METHOD(NativeCrypto, RAND_load_file, "(Ljava/lang/String;J)I"),
8057    NATIVE_METHOD(NativeCrypto, RAND_bytes, "([B)V"),
8058    NATIVE_METHOD(NativeCrypto, OBJ_txt2nid, "(Ljava/lang/String;)I"),
8059    NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_longName, "(Ljava/lang/String;)Ljava/lang/String;"),
8060    NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_oid, "(Ljava/lang/String;)Ljava/lang/String;"),
8061    NATIVE_METHOD(NativeCrypto, create_BIO_InputStream, ("(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream;)J")),
8062    NATIVE_METHOD(NativeCrypto, create_BIO_OutputStream, "(Ljava/io/OutputStream;)J"),
8063    NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"),
8064    NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"),
8065    NATIVE_METHOD(NativeCrypto, BIO_free, "(J)V"),
8066    NATIVE_METHOD(NativeCrypto, X509_NAME_print_ex, "(JJ)Ljava/lang/String;"),
8067    NATIVE_METHOD(NativeCrypto, d2i_X509_bio, "(J)J"),
8068    NATIVE_METHOD(NativeCrypto, d2i_X509, "([B)J"),
8069    NATIVE_METHOD(NativeCrypto, i2d_X509, "(J)[B"),
8070    NATIVE_METHOD(NativeCrypto, i2d_X509_PUBKEY, "(J)[B"),
8071    NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509, "(J)J"),
8072    NATIVE_METHOD(NativeCrypto, PEM_read_bio_PKCS7, "(JI)[J"),
8073    NATIVE_METHOD(NativeCrypto, d2i_PKCS7_bio, "(JI)[J"),
8074    NATIVE_METHOD(NativeCrypto, i2d_PKCS7, "([J)[B"),
8075    NATIVE_METHOD(NativeCrypto, ASN1_seq_unpack_X509_bio, "(J)[J"),
8076    NATIVE_METHOD(NativeCrypto, ASN1_seq_pack_X509, "([J)[B"),
8077    NATIVE_METHOD(NativeCrypto, X509_free, "(J)V"),
8078    NATIVE_METHOD(NativeCrypto, X509_cmp, "(JJ)I"),
8079    NATIVE_METHOD(NativeCrypto, get_X509_hashCode, "(J)I"),
8080    NATIVE_METHOD(NativeCrypto, X509_print_ex, "(JJJJ)V"),
8081    NATIVE_METHOD(NativeCrypto, X509_get_pubkey, "(J)J"),
8082    NATIVE_METHOD(NativeCrypto, X509_get_issuer_name, "(J)[B"),
8083    NATIVE_METHOD(NativeCrypto, X509_get_subject_name, "(J)[B"),
8084    NATIVE_METHOD(NativeCrypto, get_X509_pubkey_oid, "(J)Ljava/lang/String;"),
8085    NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_oid, "(J)Ljava/lang/String;"),
8086    NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_parameter, "(J)[B"),
8087    NATIVE_METHOD(NativeCrypto, get_X509_issuerUID, "(J)[Z"),
8088    NATIVE_METHOD(NativeCrypto, get_X509_subjectUID, "(J)[Z"),
8089    NATIVE_METHOD(NativeCrypto, get_X509_ex_kusage, "(J)[Z"),
8090    NATIVE_METHOD(NativeCrypto, get_X509_ex_xkusage, "(J)[Ljava/lang/String;"),
8091    NATIVE_METHOD(NativeCrypto, get_X509_ex_pathlen, "(J)I"),
8092    NATIVE_METHOD(NativeCrypto, X509_get_ext_oid, "(JLjava/lang/String;)[B"),
8093    NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext_oid, "(JLjava/lang/String;)[B"),
8094    NATIVE_METHOD(NativeCrypto, get_X509_CRL_crl_enc, "(J)[B"),
8095    NATIVE_METHOD(NativeCrypto, X509_CRL_verify, "(JJ)V"),
8096    NATIVE_METHOD(NativeCrypto, X509_CRL_get_lastUpdate, "(J)J"),
8097    NATIVE_METHOD(NativeCrypto, X509_CRL_get_nextUpdate, "(J)J"),
8098    NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext_oid, "(JLjava/lang/String;)[B"),
8099    NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_serialNumber, "(J)[B"),
8100    NATIVE_METHOD(NativeCrypto, X509_REVOKED_print, "(JJ)V"),
8101    NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_revocationDate, "(J)J"),
8102    NATIVE_METHOD(NativeCrypto, get_X509_ext_oids, "(JI)[Ljava/lang/String;"),
8103    NATIVE_METHOD(NativeCrypto, get_X509_CRL_ext_oids, "(JI)[Ljava/lang/String;"),
8104    NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_ext_oids, "(JI)[Ljava/lang/String;"),
8105    NATIVE_METHOD(NativeCrypto, get_X509_GENERAL_NAME_stack, "(JI)[[Ljava/lang/Object;"),
8106    NATIVE_METHOD(NativeCrypto, X509_get_notBefore, "(J)J"),
8107    NATIVE_METHOD(NativeCrypto, X509_get_notAfter, "(J)J"),
8108    NATIVE_METHOD(NativeCrypto, X509_get_version, "(J)J"),
8109    NATIVE_METHOD(NativeCrypto, X509_get_serialNumber, "(J)[B"),
8110    NATIVE_METHOD(NativeCrypto, X509_verify, "(JJ)V"),
8111    NATIVE_METHOD(NativeCrypto, get_X509_cert_info_enc, "(J)[B"),
8112    NATIVE_METHOD(NativeCrypto, get_X509_signature, "(J)[B"),
8113    NATIVE_METHOD(NativeCrypto, get_X509_CRL_signature, "(J)[B"),
8114    NATIVE_METHOD(NativeCrypto, get_X509_ex_flags, "(J)I"),
8115    NATIVE_METHOD(NativeCrypto, X509_check_issued, "(JJ)I"),
8116    NATIVE_METHOD(NativeCrypto, d2i_X509_CRL_bio, "(J)J"),
8117    NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509_CRL, "(J)J"),
8118    NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_cert, "(JJ)J"),
8119    NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_serial, "(J[B)J"),
8120    NATIVE_METHOD(NativeCrypto, X509_CRL_get_REVOKED, "(J)[J"),
8121    NATIVE_METHOD(NativeCrypto, i2d_X509_CRL, "(J)[B"),
8122    NATIVE_METHOD(NativeCrypto, X509_CRL_free, "(J)V"),
8123    NATIVE_METHOD(NativeCrypto, X509_CRL_print, "(JJ)V"),
8124    NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_oid, "(J)Ljava/lang/String;"),
8125    NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_parameter, "(J)[B"),
8126    NATIVE_METHOD(NativeCrypto, X509_CRL_get_issuer_name, "(J)[B"),
8127    NATIVE_METHOD(NativeCrypto, X509_CRL_get_version, "(J)J"),
8128    NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext, "(JLjava/lang/String;)J"),
8129    NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext, "(JLjava/lang/String;)J"),
8130    NATIVE_METHOD(NativeCrypto, X509_REVOKED_dup, "(J)J"),
8131    NATIVE_METHOD(NativeCrypto, i2d_X509_REVOKED, "(J)[B"),
8132    NATIVE_METHOD(NativeCrypto, X509_supported_extension, "(J)I"),
8133    NATIVE_METHOD(NativeCrypto, ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"),
8134    NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()J"),
8135    NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(J)V"),
8136    NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(J[B)V"),
8137    NATIVE_METHOD(NativeCrypto, SSL_new, "(J)J"),
8138    NATIVE_METHOD(NativeCrypto, SSL_enable_tls_channel_id, "(J)V"),
8139    NATIVE_METHOD(NativeCrypto, SSL_get_tls_channel_id, "(J)[B"),
8140    NATIVE_METHOD(NativeCrypto, SSL_set1_tls_channel_id, "(JJ)V"),
8141    NATIVE_METHOD(NativeCrypto, SSL_use_PrivateKey, "(JJ)V"),
8142    NATIVE_METHOD(NativeCrypto, SSL_use_certificate, "(J[J)V"),
8143    NATIVE_METHOD(NativeCrypto, SSL_check_private_key, "(J)V"),
8144    NATIVE_METHOD(NativeCrypto, SSL_set_client_CA_list, "(J[[B)V"),
8145    NATIVE_METHOD(NativeCrypto, SSL_get_mode, "(J)J"),
8146    NATIVE_METHOD(NativeCrypto, SSL_set_mode, "(JJ)J"),
8147    NATIVE_METHOD(NativeCrypto, SSL_clear_mode, "(JJ)J"),
8148    NATIVE_METHOD(NativeCrypto, SSL_get_options, "(J)J"),
8149    NATIVE_METHOD(NativeCrypto, SSL_set_options, "(JJ)J"),
8150    NATIVE_METHOD(NativeCrypto, SSL_clear_options, "(JJ)J"),
8151    NATIVE_METHOD(NativeCrypto, SSL_set_cipher_lists, "(J[Ljava/lang/String;)V"),
8152    NATIVE_METHOD(NativeCrypto, SSL_get_ciphers, "(J)[J"),
8153    NATIVE_METHOD(NativeCrypto, get_SSL_CIPHER_algorithm_auth, "(J)I"),
8154    NATIVE_METHOD(NativeCrypto, get_SSL_CIPHER_algorithm_mkey, "(J)I"),
8155    NATIVE_METHOD(NativeCrypto, SSL_set_verify, "(JI)V"),
8156    NATIVE_METHOD(NativeCrypto, SSL_set_session, "(JJ)V"),
8157    NATIVE_METHOD(NativeCrypto, SSL_set_session_creation_enabled, "(JZ)V"),
8158    NATIVE_METHOD(NativeCrypto, SSL_set_tlsext_host_name, "(JLjava/lang/String;)V"),
8159    NATIVE_METHOD(NativeCrypto, SSL_get_servername, "(J)Ljava/lang/String;"),
8160    NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "IZ[B[B)I"),
8161    NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(J)V"),
8162    NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(J)[J"),
8163    NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(J)[J"),
8164    NATIVE_METHOD(NativeCrypto, SSL_read, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)I"),
8165    NATIVE_METHOD(NativeCrypto, SSL_write, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)V"),
8166    NATIVE_METHOD(NativeCrypto, SSL_interrupt, "(J)V"),
8167    NATIVE_METHOD(NativeCrypto, SSL_shutdown, "(J" FILE_DESCRIPTOR SSL_CALLBACKS ")V"),
8168    NATIVE_METHOD(NativeCrypto, SSL_free, "(J)V"),
8169    NATIVE_METHOD(NativeCrypto, SSL_SESSION_session_id, "(J)[B"),
8170    NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_time, "(J)J"),
8171    NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_version, "(J)Ljava/lang/String;"),
8172    NATIVE_METHOD(NativeCrypto, SSL_SESSION_cipher, "(J)Ljava/lang/String;"),
8173    NATIVE_METHOD(NativeCrypto, SSL_SESSION_free, "(J)V"),
8174    NATIVE_METHOD(NativeCrypto, i2d_SSL_SESSION, "(J)[B"),
8175    NATIVE_METHOD(NativeCrypto, d2i_SSL_SESSION, "([B)J"),
8176    NATIVE_METHOD(NativeCrypto, SSL_CTX_enable_npn, "(J)V"),
8177    NATIVE_METHOD(NativeCrypto, SSL_CTX_disable_npn, "(J)V"),
8178    NATIVE_METHOD(NativeCrypto, SSL_get_npn_negotiated_protocol, "(J)[B"),
8179    NATIVE_METHOD(NativeCrypto, SSL_CTX_set_alpn_protos, "(J[B)I"),
8180    NATIVE_METHOD(NativeCrypto, SSL_get0_alpn_selected, "(J)[B"),
8181    NATIVE_METHOD(NativeCrypto, ERR_peek_last_error, "()J"),
8182};
8183
8184static void initialize_conscrypt(JNIEnv* env) {
8185    jniRegisterNativeMethods(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto",
8186                             sNativeCryptoMethods, NELEM(sNativeCryptoMethods));
8187
8188    ScopedLocalRef<jclass> localClass(env,
8189            env->FindClass(TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream"));
8190    openSslOutputStreamClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
8191    if (openSslOutputStreamClass == NULL) {
8192        ALOGE("failed to find class OpenSSLBIOInputStream");
8193        abort();
8194    }
8195
8196    calendar_setMethod = env->GetMethodID(calendarClass, "set", "(IIIIII)V");
8197    inputStream_readMethod = env->GetMethodID(inputStreamClass, "read", "([B)I");
8198    integer_valueOfMethod = env->GetStaticMethodID(integerClass, "valueOf",
8199            "(I)Ljava/lang/Integer;");
8200    openSslInputStream_readLineMethod = env->GetMethodID(openSslOutputStreamClass, "gets",
8201            "([B)I");
8202    outputStream_writeMethod = env->GetMethodID(outputStreamClass, "write", "([B)V");
8203    outputStream_flushMethod = env->GetMethodID(outputStreamClass, "flush", "()V");
8204}
8205
8206static jclass findClass(JNIEnv* env, const char* name) {
8207    ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
8208    jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
8209    if (result == NULL) {
8210        ALOGE("failed to find class '%s'", name);
8211        abort();
8212    }
8213    return result;
8214}
8215
8216// Use JNI_OnLoad for when we're standalone
8217int JNI_OnLoad(JavaVM *vm, void*) {
8218    JNI_TRACE("JNI_OnLoad NativeCrypto");
8219    gJavaVM = vm;
8220
8221    JNIEnv *env;
8222    if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
8223        ALOGE("Could not get JNIEnv");
8224        return JNI_ERR;
8225    }
8226
8227    byteArrayClass = findClass(env, "[B");
8228    calendarClass = findClass(env, "java/util/Calendar");
8229    inputStreamClass = findClass(env, "java/io/InputStream");
8230    integerClass = findClass(env, "java/lang/Integer");
8231    objectClass = findClass(env, "java/lang/Object");
8232    objectArrayClass = findClass(env, "[Ljava/lang/Object;");
8233    outputStreamClass = findClass(env, "java/io/OutputStream");
8234    stringClass = findClass(env, "java/lang/String");
8235
8236    initialize_conscrypt(env);
8237    return JNI_VERSION_1_6;
8238}
8239