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