Home | History | Annotate | Download | only in native
      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 <algorithm>
     31 #include <arpa/inet.h>
     32 #include <fcntl.h>
     33 #include <sys/socket.h>
     34 #include <unistd.h>
     35 #include <vector>
     36 
     37 #include <jni.h>
     38 
     39 #include <openssl/asn1t.h>
     40 #include <openssl/dsa.h>
     41 #include <openssl/engine.h>
     42 #include <openssl/err.h>
     43 #include <openssl/evp.h>
     44 #include <openssl/rand.h>
     45 #include <openssl/rsa.h>
     46 #include <openssl/ssl.h>
     47 #include <openssl/x509v3.h>
     48 
     49 #include "AsynchronousSocketCloseMonitor.h"
     50 #include "cutils/log.h"
     51 #include "JNIHelp.h"
     52 #include "JniConstants.h"
     53 #include "JniException.h"
     54 #include "NetFd.h"
     55 #include "ScopedLocalRef.h"
     56 #include "ScopedPrimitiveArray.h"
     57 #include "ScopedUtfChars.h"
     58 #include "UniquePtr.h"
     59 
     60 #undef WITH_JNI_TRACE
     61 #undef WITH_JNI_TRACE_DATA
     62 
     63 /*
     64  * How to use this for debugging with Wireshark:
     65  *
     66  * 1. Pull lines from logcat to a file that looks like (without quotes):
     67  *     "RSA Session-ID:... Master-Key:..." <CR>
     68  *     "RSA Session-ID:... Master-Key:..." <CR>
     69  *     <etc>
     70  * 2. Start Wireshark
     71  * 3. Go to Edit -> Preferences -> SSL -> (Pre-)Master-Key log and fill in
     72  *    the file you put the lines in above.
     73  * 4. Follow the stream that corresponds to the desired "Session-ID" in
     74  *    the Server Hello.
     75  */
     76 #undef WITH_JNI_TRACE_KEYS
     77 
     78 #ifdef WITH_JNI_TRACE
     79 #define JNI_TRACE(...) \
     80         ((void)ALOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__));     \
     81 /*
     82         ((void)printf("I/" LOG_TAG "-jni:"));         \
     83         ((void)printf(__VA_ARGS__));          \
     84         ((void)printf("\n"))
     85 */
     86 #else
     87 #define JNI_TRACE(...) ((void)0)
     88 #endif
     89 // don't overwhelm logcat
     90 #define WITH_JNI_TRACE_DATA_CHUNK_SIZE 512
     91 
     92 static JavaVM* gJavaVM;
     93 static jclass openSslOutputStreamClass;
     94 
     95 static jclass byteArrayClass;
     96 static jclass calendarClass;
     97 static jclass objectClass;
     98 static jclass objectArrayClass;
     99 static jclass integerClass;
    100 static jclass inputStreamClass;
    101 static jclass outputStreamClass;
    102 static jclass stringClass;
    103 
    104 static jmethodID calendar_setMethod;
    105 static jmethodID inputStream_readMethod;
    106 static jmethodID integer_valueOfMethod;
    107 static jmethodID openSslInputStream_readLineMethod;
    108 static jmethodID outputStream_writeMethod;
    109 static jmethodID outputStream_flushMethod;
    110 
    111 struct OPENSSL_Delete {
    112     void operator()(void* p) const {
    113         OPENSSL_free(p);
    114     }
    115 };
    116 typedef UniquePtr<unsigned char, OPENSSL_Delete> Unique_OPENSSL_str;
    117 
    118 struct BIO_Delete {
    119     void operator()(BIO* p) const {
    120         BIO_free(p);
    121     }
    122 };
    123 typedef UniquePtr<BIO, BIO_Delete> Unique_BIO;
    124 
    125 struct BIGNUM_Delete {
    126     void operator()(BIGNUM* p) const {
    127         BN_free(p);
    128     }
    129 };
    130 typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
    131 
    132 struct ASN1_INTEGER_Delete {
    133     void operator()(ASN1_INTEGER* p) const {
    134         ASN1_INTEGER_free(p);
    135     }
    136 };
    137 typedef UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> Unique_ASN1_INTEGER;
    138 
    139 struct DH_Delete {
    140     void operator()(DH* p) const {
    141         DH_free(p);
    142     }
    143 };
    144 typedef UniquePtr<DH, DH_Delete> Unique_DH;
    145 
    146 struct DSA_Delete {
    147     void operator()(DSA* p) const {
    148         DSA_free(p);
    149     }
    150 };
    151 typedef UniquePtr<DSA, DSA_Delete> Unique_DSA;
    152 
    153 struct EC_GROUP_Delete {
    154     void operator()(EC_GROUP* p) const {
    155         EC_GROUP_clear_free(p);
    156     }
    157 };
    158 typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP;
    159 
    160 struct EC_POINT_Delete {
    161     void operator()(EC_POINT* p) const {
    162         EC_POINT_clear_free(p);
    163     }
    164 };
    165 typedef UniquePtr<EC_POINT, EC_POINT_Delete> Unique_EC_POINT;
    166 
    167 struct EC_KEY_Delete {
    168     void operator()(EC_KEY* p) const {
    169         EC_KEY_free(p);
    170     }
    171 };
    172 typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
    173 
    174 struct EVP_MD_CTX_Delete {
    175     void operator()(EVP_MD_CTX* p) const {
    176         EVP_MD_CTX_destroy(p);
    177     }
    178 };
    179 typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX;
    180 
    181 struct EVP_CIPHER_CTX_Delete {
    182     void operator()(EVP_CIPHER_CTX* p) const {
    183         EVP_CIPHER_CTX_cleanup(p);
    184     }
    185 };
    186 typedef UniquePtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_Delete> Unique_EVP_CIPHER_CTX;
    187 
    188 struct EVP_PKEY_Delete {
    189     void operator()(EVP_PKEY* p) const {
    190         EVP_PKEY_free(p);
    191     }
    192 };
    193 typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
    194 
    195 struct PKCS8_PRIV_KEY_INFO_Delete {
    196     void operator()(PKCS8_PRIV_KEY_INFO* p) const {
    197         PKCS8_PRIV_KEY_INFO_free(p);
    198     }
    199 };
    200 typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
    201 
    202 struct RSA_Delete {
    203     void operator()(RSA* p) const {
    204         RSA_free(p);
    205     }
    206 };
    207 typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
    208 
    209 struct ASN1_BIT_STRING_Delete {
    210     void operator()(ASN1_BIT_STRING* p) const {
    211         ASN1_BIT_STRING_free(p);
    212     }
    213 };
    214 typedef UniquePtr<ASN1_BIT_STRING, ASN1_BIT_STRING_Delete> Unique_ASN1_BIT_STRING;
    215 
    216 struct ASN1_OBJECT_Delete {
    217     void operator()(ASN1_OBJECT* p) const {
    218         ASN1_OBJECT_free(p);
    219     }
    220 };
    221 typedef UniquePtr<ASN1_OBJECT, ASN1_OBJECT_Delete> Unique_ASN1_OBJECT;
    222 
    223 struct ASN1_GENERALIZEDTIME_Delete {
    224     void operator()(ASN1_GENERALIZEDTIME* p) const {
    225         ASN1_GENERALIZEDTIME_free(p);
    226     }
    227 };
    228 typedef UniquePtr<ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME_Delete> Unique_ASN1_GENERALIZEDTIME;
    229 
    230 struct SSL_Delete {
    231     void operator()(SSL* p) const {
    232         SSL_free(p);
    233     }
    234 };
    235 typedef UniquePtr<SSL, SSL_Delete> Unique_SSL;
    236 
    237 struct SSL_CTX_Delete {
    238     void operator()(SSL_CTX* p) const {
    239         SSL_CTX_free(p);
    240     }
    241 };
    242 typedef UniquePtr<SSL_CTX, SSL_CTX_Delete> Unique_SSL_CTX;
    243 
    244 struct X509_Delete {
    245     void operator()(X509* p) const {
    246         X509_free(p);
    247     }
    248 };
    249 typedef UniquePtr<X509, X509_Delete> Unique_X509;
    250 
    251 class X509Chain {
    252   public:
    253     X509Chain(size_t n) : x509s_(n) {}
    254 
    255     ~X509Chain() {
    256         for (const auto& x509 : x509s_) {
    257             X509_free(x509);
    258         }
    259     }
    260 
    261     X509*& operator[](size_t n) {
    262         return x509s_[n];
    263     }
    264 
    265     X509* operator[](size_t n) const {
    266         return x509s_[n];
    267     }
    268 
    269     X509* release(size_t i) {
    270         X509* x = x509s_[i];
    271         x509s_[i] = NULL;
    272         return x;
    273     }
    274 
    275   private:
    276     std::vector<X509*> x509s_;
    277 };
    278 
    279 struct X509_NAME_Delete {
    280     void operator()(X509_NAME* p) const {
    281         X509_NAME_free(p);
    282     }
    283 };
    284 typedef UniquePtr<X509_NAME, X509_NAME_Delete> Unique_X509_NAME;
    285 
    286 struct PKCS7_Delete {
    287     void operator()(PKCS7* p) const {
    288         PKCS7_free(p);
    289     }
    290 };
    291 typedef UniquePtr<PKCS7, PKCS7_Delete> Unique_PKCS7;
    292 
    293 struct sk_SSL_CIPHER_Delete {
    294     void operator()(STACK_OF(SSL_CIPHER)* p) const {
    295         // We don't own SSL_CIPHER references, so no need for pop_free
    296         sk_SSL_CIPHER_free(p);
    297     }
    298 };
    299 typedef UniquePtr<STACK_OF(SSL_CIPHER), sk_SSL_CIPHER_Delete> Unique_sk_SSL_CIPHER;
    300 
    301 struct sk_X509_Delete {
    302     void operator()(STACK_OF(X509)* p) const {
    303         sk_X509_pop_free(p, X509_free);
    304     }
    305 };
    306 typedef UniquePtr<STACK_OF(X509), sk_X509_Delete> Unique_sk_X509;
    307 
    308 struct sk_X509_NAME_Delete {
    309     void operator()(STACK_OF(X509_NAME)* p) const {
    310         sk_X509_NAME_pop_free(p, X509_NAME_free);
    311     }
    312 };
    313 typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME;
    314 
    315 struct sk_ASN1_OBJECT_Delete {
    316     void operator()(STACK_OF(ASN1_OBJECT)* p) const {
    317         sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free);
    318     }
    319 };
    320 typedef UniquePtr<STACK_OF(ASN1_OBJECT), sk_ASN1_OBJECT_Delete> Unique_sk_ASN1_OBJECT;
    321 
    322 struct sk_GENERAL_NAME_Delete {
    323     void operator()(STACK_OF(GENERAL_NAME)* p) const {
    324         sk_GENERAL_NAME_pop_free(p, GENERAL_NAME_free);
    325     }
    326 };
    327 typedef UniquePtr<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_Delete> Unique_sk_GENERAL_NAME;
    328 
    329 /**
    330  * Many OpenSSL APIs take ownership of an argument on success but don't free the argument
    331  * on failure. This means we need to tell our scoped pointers when we've transferred ownership,
    332  * without triggering a warning by not using the result of release().
    333  */
    334 #define OWNERSHIP_TRANSFERRED(obj) \
    335     typeof (obj.release()) _dummy __attribute__((unused)) = obj.release()
    336 
    337 /**
    338  * Frees the SSL error state.
    339  *
    340  * OpenSSL keeps an "error stack" per thread, and given that this code
    341  * can be called from arbitrary threads that we don't keep track of,
    342  * we err on the side of freeing the error state promptly (instead of,
    343  * say, at thread death).
    344  */
    345 static void freeOpenSslErrorState(void) {
    346     ERR_clear_error();
    347     ERR_remove_state(0);
    348 }
    349 
    350 /**
    351  * Throws a OutOfMemoryError with the given string as a message.
    352  */
    353 static void jniThrowOutOfMemory(JNIEnv* env, const char* message) {
    354     jniThrowException(env, "java/lang/OutOfMemoryError", message);
    355 }
    356 
    357 /**
    358  * Throws a BadPaddingException with the given string as a message.
    359  */
    360 static void throwBadPaddingException(JNIEnv* env, const char* message) {
    361     JNI_TRACE("throwBadPaddingException %s", message);
    362     jniThrowException(env, "javax/crypto/BadPaddingException", message);
    363 }
    364 
    365 /**
    366  * Throws a SignatureException with the given string as a message.
    367  */
    368 static void throwSignatureException(JNIEnv* env, const char* message) {
    369     JNI_TRACE("throwSignatureException %s", message);
    370     jniThrowException(env, "java/security/SignatureException", message);
    371 }
    372 
    373 /**
    374  * Throws a InvalidKeyException with the given string as a message.
    375  */
    376 static void throwInvalidKeyException(JNIEnv* env, const char* message) {
    377     JNI_TRACE("throwInvalidKeyException %s", message);
    378     jniThrowException(env, "java/security/InvalidKeyException", message);
    379 }
    380 
    381 /**
    382  * Throws a SignatureException with the given string as a message.
    383  */
    384 static void throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
    385     JNI_TRACE("throwIllegalBlockSizeException %s", message);
    386     jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message);
    387 }
    388 
    389 /**
    390  * Throws a NoSuchAlgorithmException with the given string as a message.
    391  */
    392 static void throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
    393     JNI_TRACE("throwUnknownAlgorithmException %s", message);
    394     jniThrowException(env, "java/security/NoSuchAlgorithmException", message);
    395 }
    396 
    397 static void throwForAsn1Error(JNIEnv* env, int reason, const char *message) {
    398     switch (reason) {
    399     case ASN1_R_UNABLE_TO_DECODE_RSA_KEY:
    400     case ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY:
    401     case ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE:
    402     case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE:
    403     case ASN1_R_WRONG_PUBLIC_KEY_TYPE:
    404         throwInvalidKeyException(env, message);
    405         break;
    406     case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
    407         throwNoSuchAlgorithmException(env, message);
    408         break;
    409     default:
    410         jniThrowRuntimeException(env, message);
    411         break;
    412     }
    413 }
    414 
    415 static void throwForEvpError(JNIEnv* env, int reason, const char *message) {
    416     switch (reason) {
    417     case EVP_R_BAD_DECRYPT:
    418         throwBadPaddingException(env, message);
    419         break;
    420     case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
    421     case EVP_R_WRONG_FINAL_BLOCK_LENGTH:
    422         throwIllegalBlockSizeException(env, message);
    423         break;
    424     case EVP_R_BAD_KEY_LENGTH:
    425     case EVP_R_BN_DECODE_ERROR:
    426     case EVP_R_BN_PUBKEY_ERROR:
    427     case EVP_R_INVALID_KEY_LENGTH:
    428     case EVP_R_MISSING_PARAMETERS:
    429     case EVP_R_UNSUPPORTED_KEY_SIZE:
    430     case EVP_R_UNSUPPORTED_KEYLENGTH:
    431         throwInvalidKeyException(env, message);
    432         break;
    433     case EVP_R_WRONG_PUBLIC_KEY_TYPE:
    434         throwSignatureException(env, message);
    435         break;
    436     case EVP_R_UNSUPPORTED_ALGORITHM:
    437         throwNoSuchAlgorithmException(env, message);
    438         break;
    439     default:
    440         jniThrowRuntimeException(env, message);
    441         break;
    442     }
    443 }
    444 
    445 static void throwForRsaError(JNIEnv* env, int reason, const char *message) {
    446     switch (reason) {
    447     case RSA_R_BLOCK_TYPE_IS_NOT_01:
    448     case RSA_R_BLOCK_TYPE_IS_NOT_02:
    449         throwBadPaddingException(env, message);
    450         break;
    451     case RSA_R_ALGORITHM_MISMATCH:
    452     case RSA_R_BAD_SIGNATURE:
    453     case RSA_R_DATA_GREATER_THAN_MOD_LEN:
    454     case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
    455     case RSA_R_INVALID_MESSAGE_LENGTH:
    456     case RSA_R_WRONG_SIGNATURE_LENGTH:
    457         throwSignatureException(env, message);
    458         break;
    459     case RSA_R_UNKNOWN_ALGORITHM_TYPE:
    460         throwNoSuchAlgorithmException(env, message);
    461         break;
    462     case RSA_R_MODULUS_TOO_LARGE:
    463     case RSA_R_NO_PUBLIC_EXPONENT:
    464         throwInvalidKeyException(env, message);
    465         break;
    466     default:
    467         jniThrowRuntimeException(env, message);
    468         break;
    469     }
    470 }
    471 
    472 static void throwForX509Error(JNIEnv* env, int reason, const char *message) {
    473     switch (reason) {
    474     case X509_R_UNSUPPORTED_ALGORITHM:
    475         throwNoSuchAlgorithmException(env, message);
    476         break;
    477     default:
    478         jniThrowRuntimeException(env, message);
    479         break;
    480     }
    481 }
    482 
    483 /*
    484  * Checks this thread's OpenSSL error queue and throws a RuntimeException if
    485  * necessary.
    486  *
    487  * @return true if an exception was thrown, false if not.
    488  */
    489 static bool throwExceptionIfNecessary(JNIEnv* env, const char* location  __attribute__ ((unused))) {
    490     const char* file;
    491     int line;
    492     const char* data;
    493     int flags;
    494     unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
    495     int result = false;
    496 
    497     if (error != 0) {
    498         char message[256];
    499         ERR_error_string_n(error, message, sizeof(message));
    500         int library = ERR_GET_LIB(error);
    501         int reason = ERR_GET_REASON(error);
    502         JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s",
    503                   location, error, library, reason, file, line, message,
    504                   (flags & ERR_TXT_STRING) ? data : "(no data)");
    505         switch (library) {
    506         case ERR_LIB_RSA:
    507             throwForRsaError(env, reason, message);
    508             break;
    509         case ERR_LIB_ASN1:
    510             throwForAsn1Error(env, reason, message);
    511             break;
    512         case ERR_LIB_EVP:
    513             throwForEvpError(env, reason, message);
    514             break;
    515         case ERR_LIB_X509:
    516             throwForX509Error(env, reason, message);
    517             break;
    518         case ERR_LIB_DSA:
    519             throwInvalidKeyException(env, message);
    520             break;
    521         default:
    522             jniThrowRuntimeException(env, message);
    523             break;
    524         }
    525         result = true;
    526     }
    527 
    528     freeOpenSslErrorState();
    529     return result;
    530 }
    531 
    532 /**
    533  * Throws an SocketTimeoutException with the given string as a message.
    534  */
    535 static void throwSocketTimeoutException(JNIEnv* env, const char* message) {
    536     JNI_TRACE("throwSocketTimeoutException %s", message);
    537     jniThrowException(env, "java/net/SocketTimeoutException", message);
    538 }
    539 
    540 /**
    541  * Throws a javax.net.ssl.SSLException with the given string as a message.
    542  */
    543 static void throwSSLExceptionStr(JNIEnv* env, const char* message) {
    544     JNI_TRACE("throwSSLExceptionStr %s", message);
    545     jniThrowException(env, "javax/net/ssl/SSLException", message);
    546 }
    547 
    548 /**
    549  * Throws a javax.net.ssl.SSLProcotolException with the given string as a message.
    550  */
    551 static void throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
    552     JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
    553     jniThrowException(env, "javax/net/ssl/SSLProtocolException", message);
    554 }
    555 
    556 /**
    557  * Throws an SSLException with a message constructed from the current
    558  * SSL errors. This will also log the errors.
    559  *
    560  * @param env the JNI environment
    561  * @param ssl the possibly NULL SSL
    562  * @param sslErrorCode error code returned from SSL_get_error() or
    563  * SSL_ERROR_NONE to probe with ERR_get_error
    564  * @param message null-ok; general error message
    565  */
    566 static void throwSSLExceptionWithSslErrors(
    567         JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message) {
    568 
    569     if (message == NULL) {
    570         message = "SSL error";
    571     }
    572 
    573     // First consult the SSL error code for the general message.
    574     const char* sslErrorStr = NULL;
    575     switch (sslErrorCode) {
    576         case SSL_ERROR_NONE:
    577             if (ERR_peek_error() == 0) {
    578                 sslErrorStr = "OK";
    579             } else {
    580                 sslErrorStr = "";
    581             }
    582             break;
    583         case SSL_ERROR_SSL:
    584             sslErrorStr = "Failure in SSL library, usually a protocol error";
    585             break;
    586         case SSL_ERROR_WANT_READ:
    587             sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
    588             break;
    589         case SSL_ERROR_WANT_WRITE:
    590             sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
    591             break;
    592         case SSL_ERROR_WANT_X509_LOOKUP:
    593             sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
    594             break;
    595         case SSL_ERROR_SYSCALL:
    596             sslErrorStr = "I/O error during system call";
    597             break;
    598         case SSL_ERROR_ZERO_RETURN:
    599             sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
    600             break;
    601         case SSL_ERROR_WANT_CONNECT:
    602             sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
    603             break;
    604         case SSL_ERROR_WANT_ACCEPT:
    605             sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
    606             break;
    607         default:
    608             sslErrorStr = "Unknown SSL error";
    609     }
    610 
    611     // Prepend either our explicit message or a default one.
    612     char* str;
    613     if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
    614         // problem with asprintf, just throw argument message, log everything
    615         throwSSLExceptionStr(env, message);
    616         ALOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
    617         freeOpenSslErrorState();
    618         return;
    619     }
    620 
    621     char* allocStr = str;
    622 
    623     // For protocol errors, SSL might have more information.
    624     if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
    625         // Append each error as an additional line to the message.
    626         for (;;) {
    627             char errStr[256];
    628             const char* file;
    629             int line;
    630             const char* data;
    631             int flags;
    632             unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
    633             if (err == 0) {
    634                 break;
    635             }
    636 
    637             ERR_error_string_n(err, errStr, sizeof(errStr));
    638 
    639             int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
    640                                (allocStr == NULL) ? "" : allocStr,
    641                                errStr,
    642                                file,
    643                                line,
    644                                (flags & ERR_TXT_STRING) ? data : "(no data)",
    645                                flags);
    646 
    647             if (ret < 0) {
    648                 break;
    649             }
    650 
    651             free(allocStr);
    652             allocStr = str;
    653         }
    654     // For errors during system calls, errno might be our friend.
    655     } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
    656         if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
    657             free(allocStr);
    658             allocStr = str;
    659         }
    660     // If the error code is invalid, print it.
    661     } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
    662         if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
    663             free(allocStr);
    664             allocStr = str;
    665         }
    666     }
    667 
    668     if (sslErrorCode == SSL_ERROR_SSL) {
    669         throwSSLProtocolExceptionStr(env, allocStr);
    670     } else {
    671         throwSSLExceptionStr(env, allocStr);
    672     }
    673 
    674     ALOGV("%s", allocStr);
    675     free(allocStr);
    676     freeOpenSslErrorState();
    677 }
    678 
    679 /**
    680  * Helper function that grabs the casts an ssl pointer and then checks for nullness.
    681  * If this function returns NULL and <code>throwIfNull</code> is
    682  * passed as <code>true</code>, then this function will call
    683  * <code>throwSSLExceptionStr</code> before returning, so in this case of
    684  * NULL, a caller of this function should simply return and allow JNI
    685  * to do its thing.
    686  *
    687  * @param env the JNI environment
    688  * @param ssl_address; the ssl_address pointer as an integer
    689  * @param throwIfNull whether to throw if the SSL pointer is NULL
    690  * @returns the pointer, which may be NULL
    691  */
    692 static SSL_CTX* to_SSL_CTX(JNIEnv* env, jlong ssl_ctx_address, bool throwIfNull) {
    693     SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
    694     if ((ssl_ctx == NULL) && throwIfNull) {
    695         JNI_TRACE("ssl_ctx == null");
    696         jniThrowNullPointerException(env, "ssl_ctx == null");
    697     }
    698     return ssl_ctx;
    699 }
    700 
    701 static SSL* to_SSL(JNIEnv* env, jlong ssl_address, bool throwIfNull) {
    702     SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address));
    703     if ((ssl == NULL) && throwIfNull) {
    704         JNI_TRACE("ssl == null");
    705         jniThrowNullPointerException(env, "ssl == null");
    706     }
    707     return ssl;
    708 }
    709 
    710 static SSL_SESSION* to_SSL_SESSION(JNIEnv* env, jlong ssl_session_address, bool throwIfNull) {
    711     SSL_SESSION* ssl_session
    712         = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
    713     if ((ssl_session == NULL) && throwIfNull) {
    714         JNI_TRACE("ssl_session == null");
    715         jniThrowNullPointerException(env, "ssl_session == null");
    716     }
    717     return ssl_session;
    718 }
    719 
    720 /**
    721  * Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the
    722  * fly. Returns true on success. If the return value is false, there is a
    723  * pending exception.
    724  */
    725 static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) {
    726     JNI_TRACE("arrayToBignum(%p, %p)", source, *dest);
    727 
    728     ScopedByteArrayRO sourceBytes(env, source);
    729     if (sourceBytes.get() == NULL) {
    730         JNI_TRACE("arrayToBignum(%p) => NULL", source);
    731         return false;
    732     }
    733     *dest = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()),
    734                            sourceBytes.size(),
    735                            NULL);
    736     if (*dest == NULL) {
    737         jniThrowRuntimeException(env, "Conversion to BIGNUM failed");
    738         JNI_TRACE("arrayToBignum(%p) => threw exception", source);
    739         return false;
    740     }
    741 
    742     JNI_TRACE("arrayToBignum(%p) => %p", source, *dest);
    743     return true;
    744 }
    745 
    746 /**
    747  * Converts an OpenSSL BIGNUM to a Java byte[] array.
    748  */
    749 static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source, const char* sourceName) {
    750     JNI_TRACE("bignumToArray(%p, %s)", source, sourceName);
    751 
    752     if (source == NULL) {
    753         jniThrowNullPointerException(env, sourceName);
    754         return NULL;
    755     }
    756 
    757     jbyteArray javaBytes = env->NewByteArray(BN_num_bytes(source) + 1);
    758     ScopedByteArrayRW bytes(env, javaBytes);
    759     if (bytes.get() == NULL) {
    760         JNI_TRACE("bignumToArray(%p, %s) => NULL", source, sourceName);
    761         return NULL;
    762     }
    763 
    764     unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
    765 
    766     // Set the sign for the Java code.
    767     if (BN_is_negative(source)) {
    768         *tmp = 0xFF;
    769     } else {
    770         *tmp = 0x00;
    771     }
    772 
    773     if (BN_num_bytes(source) > 0 && BN_bn2bin(source, tmp + 1) <= 0) {
    774         throwExceptionIfNecessary(env, "bignumToArray");
    775         return NULL;
    776     }
    777 
    778     JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes);
    779     return javaBytes;
    780 }
    781 
    782 /**
    783  * Converts various OpenSSL ASN.1 types to a jbyteArray with DER-encoded data
    784  * inside. The "i2d_func" function pointer is a function of the "i2d_<TYPE>"
    785  * from the OpenSSL ASN.1 API.
    786  */
    787 template<typename T, int (*i2d_func)(T*, unsigned char**)>
    788 jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj) {
    789     if (obj == NULL) {
    790         jniThrowNullPointerException(env, "ASN1 input == null");
    791         JNI_TRACE("ASN1ToByteArray(%p) => null input", obj);
    792         return NULL;
    793     }
    794 
    795     int derLen = i2d_func(obj, NULL);
    796     if (derLen < 0) {
    797         throwExceptionIfNecessary(env, "ASN1ToByteArray");
    798         JNI_TRACE("ASN1ToByteArray(%p) => measurement failed", obj);
    799         return NULL;
    800     }
    801 
    802     ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(derLen));
    803     if (byteArray.get() == NULL) {
    804         JNI_TRACE("ASN1ToByteArray(%p) => creating byte array failed", obj);
    805         return NULL;
    806     }
    807 
    808     ScopedByteArrayRW bytes(env, byteArray.get());
    809     if (bytes.get() == NULL) {
    810         JNI_TRACE("ASN1ToByteArray(%p) => using byte array failed", obj);
    811         return NULL;
    812     }
    813 
    814     unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
    815     int ret = i2d_func(obj, &p);
    816     if (ret < 0) {
    817         throwExceptionIfNecessary(env, "ASN1ToByteArray");
    818         JNI_TRACE("ASN1ToByteArray(%p) => final conversion failed", obj);
    819         return NULL;
    820     }
    821 
    822     JNI_TRACE("ASN1ToByteArray(%p) => success (%d bytes written)", obj, ret);
    823     return byteArray.release();
    824 }
    825 
    826 template<typename T, T* (*d2i_func)(T**, const unsigned char**, long)>
    827 T* ByteArrayToASN1(JNIEnv* env, jbyteArray byteArray) {
    828     ScopedByteArrayRO bytes(env, byteArray);
    829     if (bytes.get() == NULL) {
    830         JNI_TRACE("ByteArrayToASN1(%p) => using byte array failed", byteArray);
    831         return 0;
    832     }
    833 
    834     const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
    835     return d2i_func(NULL, &tmp, bytes.size());
    836 }
    837 
    838 /**
    839  * Converts ASN.1 BIT STRING to a jbooleanArray.
    840  */
    841 jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) {
    842     int size = bitStr->length * 8;
    843     if (bitStr->flags & ASN1_STRING_FLAG_BITS_LEFT) {
    844         size -= bitStr->flags & 0x07;
    845     }
    846 
    847     ScopedLocalRef<jbooleanArray> bitsRef(env, env->NewBooleanArray(size));
    848     if (bitsRef.get() == NULL) {
    849         return NULL;
    850     }
    851 
    852     ScopedBooleanArrayRW bitsArray(env, bitsRef.get());
    853     for (int i = 0; i < static_cast<int>(bitsArray.size()); i++) {
    854         bitsArray[i] = ASN1_BIT_STRING_get_bit(bitStr, i);
    855     }
    856 
    857     return bitsRef.release();
    858 }
    859 
    860 /**
    861  * To avoid the round-trip to ASN.1 and back in X509_dup, we just up the reference count.
    862  */
    863 static X509* X509_dup_nocopy(X509* x509) {
    864     CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
    865     return x509;
    866 }
    867 
    868 /**
    869  * BIO for InputStream
    870  */
    871 class BIO_Stream {
    872 public:
    873     BIO_Stream(jobject stream) :
    874             mEof(false) {
    875         JNIEnv* env = getEnv();
    876         mStream = env->NewGlobalRef(stream);
    877     }
    878 
    879     ~BIO_Stream() {
    880         JNIEnv* env = getEnv();
    881 
    882         env->DeleteGlobalRef(mStream);
    883     }
    884 
    885     bool isEof() const {
    886         JNI_TRACE("isEof? %s", mEof ? "yes" : "no");
    887         return mEof;
    888     }
    889 
    890     int flush() {
    891         JNIEnv* env = getEnv();
    892         if (env == NULL) {
    893             return -1;
    894         }
    895 
    896         env->CallVoidMethod(mStream, outputStream_flushMethod);
    897         if (env->ExceptionCheck()) {
    898             return -1;
    899         }
    900 
    901         return 1;
    902     }
    903 
    904 protected:
    905     jobject getStream() {
    906         return mStream;
    907     }
    908 
    909     void setEof(bool eof) {
    910         mEof = eof;
    911     }
    912 
    913     JNIEnv* getEnv() {
    914         JNIEnv* env;
    915 
    916         if (gJavaVM->AttachCurrentThread(&env, NULL) < 0) {
    917             return NULL;
    918         }
    919 
    920         return env;
    921     }
    922 
    923 private:
    924     jobject mStream;
    925     bool mEof;
    926 };
    927 
    928 class BIO_InputStream : public BIO_Stream {
    929 public:
    930     BIO_InputStream(jobject stream) :
    931             BIO_Stream(stream) {
    932     }
    933 
    934     int read(char *buf, int len) {
    935         return read_internal(buf, len, inputStream_readMethod);
    936     }
    937 
    938     int gets(char *buf, int len) {
    939         if (len > PEM_LINE_LENGTH) {
    940             len = PEM_LINE_LENGTH;
    941         }
    942 
    943         int read = read_internal(buf, len - 1, openSslInputStream_readLineMethod);
    944         buf[read] = '\0';
    945         JNI_TRACE("BIO::gets \"%s\"", buf);
    946         return read;
    947     }
    948 
    949 private:
    950     int read_internal(char *buf, int len, jmethodID method) {
    951         JNIEnv* env = getEnv();
    952         if (env == NULL) {
    953             JNI_TRACE("BIO_InputStream::read could not get JNIEnv");
    954             return -1;
    955         }
    956 
    957         ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len));
    958         if (javaBytes.get() == NULL) {
    959             JNI_TRACE("BIO_InputStream::read failed call to NewByteArray");
    960             return -1;
    961         }
    962 
    963         jint read = env->CallIntMethod(getStream(), method, javaBytes.get());
    964         if (env->ExceptionCheck()) {
    965             JNI_TRACE("BIO_InputStream::read failed call to InputStream#read");
    966             return -1;
    967         }
    968 
    969         /* Java uses -1 to indicate EOF condition. */
    970         if (read == -1) {
    971             setEof(true);
    972             read = 0;
    973         } else if (read > 0) {
    974             env->GetByteArrayRegion(javaBytes.get(), 0, read, reinterpret_cast<jbyte*>(buf));
    975         }
    976 
    977         return read;
    978     }
    979 
    980 public:
    981     /** Length of PEM-encoded line (64) plus CR plus NULL */
    982     static const int PEM_LINE_LENGTH = 66;
    983 };
    984 
    985 class BIO_OutputStream : public BIO_Stream {
    986 public:
    987     BIO_OutputStream(jobject stream) :
    988             BIO_Stream(stream) {
    989     }
    990 
    991     int write(const char *buf, int len) {
    992         JNIEnv* env = getEnv();
    993         if (env == NULL) {
    994             JNI_TRACE("BIO_OutputStream::write => could not get JNIEnv");
    995             return -1;
    996         }
    997 
    998         ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len));
    999         if (javaBytes.get() == NULL) {
   1000             JNI_TRACE("BIO_OutputStream::write => failed call to NewByteArray");
   1001             return -1;
   1002         }
   1003 
   1004         env->SetByteArrayRegion(javaBytes.get(), 0, len, reinterpret_cast<const jbyte*>(buf));
   1005 
   1006         env->CallVoidMethod(getStream(), outputStream_writeMethod, javaBytes.get());
   1007         if (env->ExceptionCheck()) {
   1008             JNI_TRACE("BIO_OutputStream::write => failed call to OutputStream#write");
   1009             return -1;
   1010         }
   1011 
   1012         return len;
   1013     }
   1014 };
   1015 
   1016 static int bio_stream_create(BIO *b) {
   1017     b->init = 1;
   1018     b->num = 0;
   1019     b->ptr = NULL;
   1020     b->flags = 0;
   1021     return 1;
   1022 }
   1023 
   1024 static int bio_stream_destroy(BIO *b) {
   1025     if (b == NULL) {
   1026         return 0;
   1027     }
   1028 
   1029     if (b->ptr != NULL) {
   1030         delete static_cast<BIO_Stream*>(b->ptr);
   1031         b->ptr = NULL;
   1032     }
   1033 
   1034     b->init = 0;
   1035     b->flags = 0;
   1036     return 1;
   1037 }
   1038 
   1039 static int bio_stream_read(BIO *b, char *buf, int len) {
   1040     BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr);
   1041     return stream->read(buf, len);
   1042 }
   1043 
   1044 static int bio_stream_write(BIO *b, const char *buf, int len) {
   1045     BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr);
   1046     return stream->write(buf, len);
   1047 }
   1048 
   1049 static int bio_stream_puts(BIO *b, const char *buf) {
   1050     BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr);
   1051     return stream->write(buf, strlen(buf));
   1052 }
   1053 
   1054 static int bio_stream_gets(BIO *b, char *buf, int len) {
   1055     BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr);
   1056     return stream->gets(buf, len);
   1057 }
   1058 
   1059 static void bio_stream_assign(BIO *b, BIO_Stream* stream) {
   1060     b->ptr = static_cast<void*>(stream);
   1061 }
   1062 
   1063 static long bio_stream_ctrl(BIO *b, int cmd, long, void *) {
   1064     BIO_Stream* stream = static_cast<BIO_Stream*>(b->ptr);
   1065 
   1066     switch (cmd) {
   1067     case BIO_CTRL_EOF:
   1068         return stream->isEof() ? 1 : 0;
   1069     case BIO_CTRL_FLUSH:
   1070         return stream->flush();
   1071     default:
   1072         return 0;
   1073     }
   1074 }
   1075 
   1076 static BIO_METHOD stream_bio_method = {
   1077         ( 100 | 0x0400 ), /* source/sink BIO */
   1078         "InputStream/OutputStream BIO",
   1079         bio_stream_write, /* bio_write */
   1080         bio_stream_read, /* bio_read */
   1081         bio_stream_puts, /* bio_puts */
   1082         bio_stream_gets, /* bio_gets */
   1083         bio_stream_ctrl, /* bio_ctrl */
   1084         bio_stream_create, /* bio_create */
   1085         bio_stream_destroy, /* bio_free */
   1086         NULL, /* no bio_callback_ctrl */
   1087 };
   1088 
   1089 /**
   1090  * Copied from libnativehelper NetworkUtilites.cpp
   1091  */
   1092 static bool setBlocking(int fd, bool blocking) {
   1093     int flags = fcntl(fd, F_GETFL);
   1094     if (flags == -1) {
   1095         return false;
   1096     }
   1097 
   1098     if (!blocking) {
   1099         flags |= O_NONBLOCK;
   1100     } else {
   1101         flags &= ~O_NONBLOCK;
   1102     }
   1103 
   1104     int rc = fcntl(fd, F_SETFL, flags);
   1105     return (rc != -1);
   1106 }
   1107 
   1108 /**
   1109  * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I
   1110  * suppose there are not many other ways to do this on a Linux system (modulo
   1111  * isomorphism).
   1112  */
   1113 #define MUTEX_TYPE pthread_mutex_t
   1114 #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
   1115 #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
   1116 #define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
   1117 #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
   1118 #define THREAD_ID pthread_self()
   1119 #define THROW_SSLEXCEPTION (-2)
   1120 #define THROW_SOCKETTIMEOUTEXCEPTION (-3)
   1121 #define THROWN_EXCEPTION (-4)
   1122 
   1123 static MUTEX_TYPE* mutex_buf = NULL;
   1124 
   1125 static void locking_function(int mode, int n, const char*, int) {
   1126     if (mode & CRYPTO_LOCK) {
   1127         MUTEX_LOCK(mutex_buf[n]);
   1128     } else {
   1129         MUTEX_UNLOCK(mutex_buf[n]);
   1130     }
   1131 }
   1132 
   1133 static unsigned long id_function(void) {
   1134     return ((unsigned long)THREAD_ID);
   1135 }
   1136 
   1137 int THREAD_setup(void) {
   1138     mutex_buf = new MUTEX_TYPE[CRYPTO_num_locks()];
   1139     if (!mutex_buf) {
   1140         return 0;
   1141     }
   1142 
   1143     for (int i = 0; i < CRYPTO_num_locks(); ++i) {
   1144         MUTEX_SETUP(mutex_buf[i]);
   1145     }
   1146 
   1147     CRYPTO_set_id_callback(id_function);
   1148     CRYPTO_set_locking_callback(locking_function);
   1149 
   1150     return 1;
   1151 }
   1152 
   1153 int THREAD_cleanup(void) {
   1154     if (!mutex_buf) {
   1155         return 0;
   1156     }
   1157 
   1158     CRYPTO_set_id_callback(NULL);
   1159     CRYPTO_set_locking_callback(NULL);
   1160 
   1161     for (int i = 0; i < CRYPTO_num_locks( ); i++) {
   1162         MUTEX_CLEANUP(mutex_buf[i]);
   1163     }
   1164 
   1165     free(mutex_buf);
   1166     mutex_buf = NULL;
   1167 
   1168     return 1;
   1169 }
   1170 
   1171 /**
   1172  * Initialization phase for every OpenSSL job: Loads the Error strings, the
   1173  * crypto algorithms and reset the OpenSSL library
   1174  */
   1175 static void NativeCrypto_clinit(JNIEnv*, jclass)
   1176 {
   1177     SSL_load_error_strings();
   1178     ERR_load_crypto_strings();
   1179     SSL_library_init();
   1180     OpenSSL_add_all_algorithms();
   1181     THREAD_setup();
   1182 }
   1183 
   1184 static void NativeCrypto_ENGINE_load_dynamic(JNIEnv*, jclass) {
   1185     JNI_TRACE("ENGINE_load_dynamic()");
   1186 
   1187     ENGINE_load_dynamic();
   1188 }
   1189 
   1190 static jlong NativeCrypto_ENGINE_by_id(JNIEnv* env, jclass, jstring idJava) {
   1191     JNI_TRACE("ENGINE_by_id(%p)", idJava);
   1192 
   1193     ScopedUtfChars id(env, idJava);
   1194     if (id.c_str() == NULL) {
   1195         JNI_TRACE("ENGINE_by_id(%p) => id == null", idJava);
   1196         return 0;
   1197     }
   1198     JNI_TRACE("ENGINE_by_id(\"%s\")", id.c_str());
   1199 
   1200     ENGINE* e = ENGINE_by_id(id.c_str());
   1201     if (e == NULL) {
   1202         freeOpenSslErrorState();
   1203     }
   1204 
   1205     JNI_TRACE("ENGINE_by_id(\"%s\") => %p", id.c_str(), e);
   1206     return reinterpret_cast<uintptr_t>(e);
   1207 }
   1208 
   1209 static jint NativeCrypto_ENGINE_add(JNIEnv* env, jclass, jlong engineRef) {
   1210     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1211     JNI_TRACE("ENGINE_add(%p)", e);
   1212 
   1213     if (e == NULL) {
   1214         jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
   1215         return 0;
   1216     }
   1217 
   1218     int ret = ENGINE_add(e);
   1219 
   1220     /*
   1221      * We tolerate errors, because the most likely error is that
   1222      * the ENGINE is already in the list.
   1223      */
   1224     freeOpenSslErrorState();
   1225 
   1226     JNI_TRACE("ENGINE_add(%p) => %d", e, ret);
   1227     return ret;
   1228 }
   1229 
   1230 static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jlong engineRef) {
   1231     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1232     JNI_TRACE("ENGINE_init(%p)", e);
   1233 
   1234     if (e == NULL) {
   1235         jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
   1236         return 0;
   1237     }
   1238 
   1239     int ret = ENGINE_init(e);
   1240     JNI_TRACE("ENGINE_init(%p) => %d", e, ret);
   1241     return ret;
   1242 }
   1243 
   1244 static jint NativeCrypto_ENGINE_finish(JNIEnv* env, jclass, jlong engineRef) {
   1245     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1246     JNI_TRACE("ENGINE_finish(%p)", e);
   1247 
   1248     if (e == NULL) {
   1249         jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
   1250         return 0;
   1251     }
   1252 
   1253     int ret = ENGINE_finish(e);
   1254     JNI_TRACE("ENGINE_finish(%p) => %d", e, ret);
   1255     return ret;
   1256 }
   1257 
   1258 static jint NativeCrypto_ENGINE_free(JNIEnv* env, jclass, jlong engineRef) {
   1259     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1260     JNI_TRACE("ENGINE_free(%p)", e);
   1261 
   1262     if (e == NULL) {
   1263         jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
   1264         return 0;
   1265     }
   1266 
   1267     int ret = ENGINE_free(e);
   1268     JNI_TRACE("ENGINE_free(%p) => %d", e, ret);
   1269     return ret;
   1270 }
   1271 
   1272 static jlong NativeCrypto_ENGINE_load_private_key(JNIEnv* env, jclass, jlong engineRef,
   1273         jstring idJava) {
   1274     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1275     JNI_TRACE("ENGINE_load_private_key(%p, %p)", e, idJava);
   1276 
   1277     ScopedUtfChars id(env, idJava);
   1278     if (id.c_str() == NULL) {
   1279         jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL");
   1280         return 0;
   1281     }
   1282 
   1283     Unique_EVP_PKEY pkey(ENGINE_load_private_key(e, id.c_str(), NULL, NULL));
   1284     if (pkey.get() == NULL) {
   1285         throwExceptionIfNecessary(env, "ENGINE_load_private_key");
   1286         return 0;
   1287     }
   1288 
   1289     JNI_TRACE("ENGINE_load_private_key(%p, %p) => %p", e, idJava, pkey.get());
   1290     return reinterpret_cast<uintptr_t>(pkey.release());
   1291 }
   1292 
   1293 static jstring NativeCrypto_ENGINE_get_id(JNIEnv* env, jclass, jlong engineRef)
   1294 {
   1295     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1296     JNI_TRACE("ENGINE_get_id(%p)", e);
   1297 
   1298     if (e == NULL) {
   1299         jniThrowNullPointerException(env, "engine == null");
   1300         JNI_TRACE("ENGINE_get_id(%p) => engine == null", e);
   1301         return NULL;
   1302     }
   1303 
   1304     const char *id = ENGINE_get_id(e);
   1305     ScopedLocalRef<jstring> idJava(env, env->NewStringUTF(id));
   1306 
   1307     JNI_TRACE("ENGINE_get_id(%p) => \"%s\"", e, id);
   1308     return idJava.release();
   1309 }
   1310 
   1311 static jint NativeCrypto_ENGINE_ctrl_cmd_string(JNIEnv* env, jclass, jlong engineRef,
   1312         jstring cmdJava, jstring argJava, jint cmd_optional)
   1313 {
   1314     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
   1315     JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d)", e, cmdJava, argJava, cmd_optional);
   1316 
   1317     if (e == NULL) {
   1318         jniThrowNullPointerException(env, "engine == null");
   1319         JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d) => engine == null", e, cmdJava, argJava,
   1320                 cmd_optional);
   1321         return 0;
   1322     }
   1323 
   1324     ScopedUtfChars cmdChars(env, cmdJava);
   1325     if (cmdChars.c_str() == NULL) {
   1326         return 0;
   1327     }
   1328 
   1329     UniquePtr<ScopedUtfChars> arg;
   1330     const char* arg_c_str = NULL;
   1331     if (argJava != NULL) {
   1332         arg.reset(new ScopedUtfChars(env, argJava));
   1333         arg_c_str = arg->c_str();
   1334         if (arg_c_str == NULL) {
   1335             return 0;
   1336         }
   1337     }
   1338     JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d)", e, cmdChars.c_str(), arg_c_str,
   1339             cmd_optional);
   1340 
   1341     int ret = ENGINE_ctrl_cmd_string(e, cmdChars.c_str(), arg_c_str, cmd_optional);
   1342     if (ret != 1) {
   1343         throwExceptionIfNecessary(env, "ENGINE_ctrl_cmd_string");
   1344         JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => threw error", e,
   1345                 cmdChars.c_str(), arg_c_str, cmd_optional);
   1346         return 0;
   1347     }
   1348 
   1349     JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => %d", e, cmdChars.c_str(),
   1350             arg_c_str, cmd_optional, ret);
   1351     return ret;
   1352 }
   1353 
   1354 /**
   1355  * public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
   1356  *                                           byte[] pub_key, byte[] priv_key);
   1357  */
   1358 static jlong NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass,
   1359                                                jbyteArray p, jbyteArray q, jbyteArray g,
   1360                                                jbyteArray pub_key, jbyteArray priv_key) {
   1361     JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p)",
   1362               p, q, g, pub_key, priv_key);
   1363 
   1364     Unique_DSA dsa(DSA_new());
   1365     if (dsa.get() == NULL) {
   1366         jniThrowRuntimeException(env, "DSA_new failed");
   1367         return 0;
   1368     }
   1369 
   1370     if (!arrayToBignum(env, p, &dsa->p)) {
   1371         return 0;
   1372     }
   1373 
   1374     if (!arrayToBignum(env, q, &dsa->q)) {
   1375         return 0;
   1376     }
   1377 
   1378     if (!arrayToBignum(env, g, &dsa->g)) {
   1379         return 0;
   1380     }
   1381 
   1382     if (pub_key != NULL && !arrayToBignum(env, pub_key, &dsa->pub_key)) {
   1383         return 0;
   1384     }
   1385 
   1386     if (priv_key != NULL && !arrayToBignum(env, priv_key, &dsa->priv_key)) {
   1387         return 0;
   1388     }
   1389 
   1390     if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL
   1391             || (dsa->pub_key == NULL && dsa->priv_key == NULL)) {
   1392         jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
   1393         return 0;
   1394     }
   1395 
   1396     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   1397     if (pkey.get() == NULL) {
   1398         jniThrowRuntimeException(env, "EVP_PKEY_new failed");
   1399         return 0;
   1400     }
   1401     if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
   1402         jniThrowRuntimeException(env, "EVP_PKEY_assign_DSA failed");
   1403         return 0;
   1404     }
   1405     OWNERSHIP_TRANSFERRED(dsa);
   1406     JNI_TRACE("EVP_PKEY_new_DSA(p=%p, q=%p, g=%p, pub_key=%p, priv_key=%p) => %p",
   1407               p, q, g, pub_key, priv_key, pkey.get());
   1408     return reinterpret_cast<jlong>(pkey.release());
   1409 }
   1410 
   1411 /**
   1412  * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
   1413  */
   1414 static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass,
   1415                                                jbyteArray n, jbyteArray e, jbyteArray d,
   1416                                                jbyteArray p, jbyteArray q,
   1417                                                jbyteArray dmp1, jbyteArray dmq1,
   1418                                                jbyteArray iqmp) {
   1419     JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, iqmp=%p)",
   1420             n, e, d, p, q, dmp1, dmq1, iqmp);
   1421 
   1422     Unique_RSA rsa(RSA_new());
   1423     if (rsa.get() == NULL) {
   1424         jniThrowRuntimeException(env, "RSA_new failed");
   1425         return 0;
   1426     }
   1427 
   1428     if (e == NULL && d == NULL) {
   1429         jniThrowException(env, "java/lang/IllegalArgumentException", "e == NULL && d == NULL");
   1430         JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == NULL && d == NULL");
   1431         return 0;
   1432     }
   1433 
   1434     if (!arrayToBignum(env, n, &rsa->n)) {
   1435         return 0;
   1436     }
   1437 
   1438     if (e != NULL && !arrayToBignum(env, e, &rsa->e)) {
   1439         return 0;
   1440     }
   1441 
   1442     if (d != NULL && !arrayToBignum(env, d, &rsa->d)) {
   1443         return 0;
   1444     }
   1445 
   1446     if (p != NULL && !arrayToBignum(env, p, &rsa->p)) {
   1447         return 0;
   1448     }
   1449 
   1450     if (q != NULL && !arrayToBignum(env, q, &rsa->q)) {
   1451         return 0;
   1452     }
   1453 
   1454     if (dmp1 != NULL && !arrayToBignum(env, dmp1, &rsa->dmp1)) {
   1455         return 0;
   1456     }
   1457 
   1458     if (dmq1 != NULL && !arrayToBignum(env, dmq1, &rsa->dmq1)) {
   1459         return 0;
   1460     }
   1461 
   1462     if (iqmp != NULL && !arrayToBignum(env, iqmp, &rsa->iqmp)) {
   1463         return 0;
   1464     }
   1465 
   1466 #ifdef WITH_JNI_TRACE
   1467     if (p != NULL && q != NULL) {
   1468         int check = RSA_check_key(rsa.get());
   1469         JNI_TRACE("EVP_PKEY_new_RSA(...) RSA_check_key returns %d", check);
   1470     }
   1471 #endif
   1472 
   1473     if (rsa->n == NULL || (rsa->e == NULL && rsa->d == NULL)) {
   1474         jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
   1475         return 0;
   1476     }
   1477 
   1478     /*
   1479      * If the private exponent is available, there is the potential to do signing
   1480      * operations. If the public exponent is also available, OpenSSL will do RSA
   1481      * blinding. Enable it if possible.
   1482      */
   1483     if (rsa->d != NULL) {
   1484         if (rsa->e != NULL) {
   1485             JNI_TRACE("EVP_PKEY_new_RSA(...) enabling RSA blinding => %p", rsa.get());
   1486             RSA_blinding_on(rsa.get(), NULL);
   1487         } else {
   1488             JNI_TRACE("EVP_PKEY_new_RSA(...) disabling RSA blinding => %p", rsa.get());
   1489             RSA_blinding_off(rsa.get());
   1490         }
   1491     }
   1492 
   1493     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   1494     if (pkey.get() == NULL) {
   1495         jniThrowRuntimeException(env, "EVP_PKEY_new failed");
   1496         return 0;
   1497     }
   1498     if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
   1499         jniThrowRuntimeException(env, "EVP_PKEY_new failed");
   1500         return 0;
   1501     }
   1502     OWNERSHIP_TRANSFERRED(rsa);
   1503     JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, iqmp=%p) => %p",
   1504             n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get());
   1505     return reinterpret_cast<uintptr_t>(pkey.release());
   1506 }
   1507 
   1508 static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jlong groupRef,
   1509         jlong pubkeyRef, jbyteArray keyJavaBytes) {
   1510     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   1511     const EC_POINT* pubkey = reinterpret_cast<const EC_POINT*>(pubkeyRef);
   1512     JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", group, pubkey, keyJavaBytes);
   1513 
   1514     Unique_BIGNUM key(NULL);
   1515     if (keyJavaBytes != NULL) {
   1516         BIGNUM* keyRef;
   1517         if (!arrayToBignum(env, keyJavaBytes, &keyRef)) {
   1518             return 0;
   1519         }
   1520         key.reset(keyRef);
   1521     }
   1522 
   1523     Unique_EC_KEY eckey(EC_KEY_new());
   1524     if (eckey.get() == NULL) {
   1525         jniThrowRuntimeException(env, "EC_KEY_new failed");
   1526         return 0;
   1527     }
   1528 
   1529     if (EC_KEY_set_group(eckey.get(), group) != 1) {
   1530         JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey,
   1531                 keyJavaBytes);
   1532         throwExceptionIfNecessary(env, "EC_KEY_set_group");
   1533         return 0;
   1534     }
   1535 
   1536     if (pubkey != NULL) {
   1537         if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) {
   1538             JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
   1539                     pubkey, keyJavaBytes);
   1540             throwExceptionIfNecessary(env, "EC_KEY_set_public_key");
   1541             return 0;
   1542         }
   1543     }
   1544 
   1545     if (key.get() != NULL) {
   1546         if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) {
   1547             JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
   1548                     pubkey, keyJavaBytes);
   1549             throwExceptionIfNecessary(env, "EC_KEY_set_private_key");
   1550             return 0;
   1551         }
   1552         if (pubkey == NULL) {
   1553             Unique_EC_POINT calcPubkey(EC_POINT_new(group));
   1554             if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), NULL, NULL, NULL)) {
   1555                 JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calulate public key", group,
   1556                         pubkey, keyJavaBytes);
   1557                 throwExceptionIfNecessary(env, "EC_KEY_set_private_key");
   1558                 return 0;
   1559             }
   1560             EC_KEY_set_public_key(eckey.get(), calcPubkey.get());
   1561         }
   1562     }
   1563 
   1564     if (!EC_KEY_check_key(eckey.get())) {
   1565         JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey, keyJavaBytes);
   1566         throwExceptionIfNecessary(env, "EC_KEY_check_key");
   1567         return 0;
   1568     }
   1569 
   1570     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   1571     if (pkey.get() == NULL) {
   1572         JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
   1573         throwExceptionIfNecessary(env, "EVP_PKEY_new failed");
   1574         return 0;
   1575     }
   1576     if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
   1577         JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
   1578         jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
   1579         return 0;
   1580     }
   1581     OWNERSHIP_TRANSFERRED(eckey);
   1582 
   1583     JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get());
   1584     return reinterpret_cast<uintptr_t>(pkey.release());
   1585 }
   1586 
   1587 static jlong NativeCrypto_EVP_PKEY_new_mac_key(JNIEnv* env, jclass, jint pkeyType,
   1588         jbyteArray keyJavaBytes)
   1589 {
   1590     JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p)", pkeyType, keyJavaBytes);
   1591 
   1592     ScopedByteArrayRO key(env, keyJavaBytes);
   1593     if (key.get() == NULL) {
   1594         return 0;
   1595     }
   1596 
   1597     const unsigned char* tmp = reinterpret_cast<const unsigned char*>(key.get());
   1598     Unique_EVP_PKEY pkey(EVP_PKEY_new_mac_key(pkeyType, (ENGINE *) NULL, tmp, key.size()));
   1599     if (pkey.get() == NULL) {
   1600         JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => threw error", pkeyType, keyJavaBytes);
   1601         throwExceptionIfNecessary(env, "ENGINE_load_private_key");
   1602         return 0;
   1603     }
   1604 
   1605     JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => %p", pkeyType, keyJavaBytes, pkey.get());
   1606     return reinterpret_cast<uintptr_t>(pkey.release());
   1607 }
   1608 
   1609 static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jlong pkeyRef) {
   1610     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1611     JNI_TRACE("EVP_PKEY_type(%p)", pkey);
   1612 
   1613     if (pkey == NULL) {
   1614         jniThrowNullPointerException(env, NULL);
   1615         return -1;
   1616     }
   1617 
   1618     int result = EVP_PKEY_type(pkey->type);
   1619     JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result);
   1620     return result;
   1621 }
   1622 
   1623 /**
   1624  * private static native int EVP_PKEY_size(int pkey);
   1625  */
   1626 static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jlong pkeyRef) {
   1627     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1628     JNI_TRACE("EVP_PKEY_size(%p)", pkey);
   1629 
   1630     if (pkey == NULL) {
   1631         jniThrowNullPointerException(env, NULL);
   1632         return -1;
   1633     }
   1634 
   1635     int result = EVP_PKEY_size(pkey);
   1636     JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result);
   1637     return result;
   1638 }
   1639 
   1640 static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jlong pkeyRef) {
   1641     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1642     JNI_TRACE("EVP_PKEY_print_public(%p)", pkey);
   1643 
   1644     if (pkey == NULL) {
   1645         jniThrowNullPointerException(env, "pkey == null");
   1646         return NULL;
   1647     }
   1648 
   1649     Unique_BIO buffer(BIO_new(BIO_s_mem()));
   1650     if (buffer.get() == NULL) {
   1651         jniThrowOutOfMemory(env, "Unable to allocate BIO");
   1652         return NULL;
   1653     }
   1654 
   1655     if (EVP_PKEY_print_public(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) {
   1656         throwExceptionIfNecessary(env, "EVP_PKEY_print_public");
   1657         return NULL;
   1658     }
   1659     // Null terminate this
   1660     BIO_write(buffer.get(), "\0", 1);
   1661 
   1662     char *tmp;
   1663     BIO_get_mem_data(buffer.get(), &tmp);
   1664     jstring description = env->NewStringUTF(tmp);
   1665 
   1666     JNI_TRACE("EVP_PKEY_print_public(%p) => \"%s\"", pkey, tmp);
   1667     return description;
   1668 }
   1669 
   1670 static jstring NativeCrypto_EVP_PKEY_print_private(JNIEnv* env, jclass, jlong pkeyRef) {
   1671     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1672     JNI_TRACE("EVP_PKEY_print_private(%p)", pkey);
   1673 
   1674     if (pkey == NULL) {
   1675         jniThrowNullPointerException(env, "pkey == null");
   1676         return NULL;
   1677     }
   1678 
   1679     Unique_BIO buffer(BIO_new(BIO_s_mem()));
   1680     if (buffer.get() == NULL) {
   1681         jniThrowOutOfMemory(env, "Unable to allocate BIO");
   1682         return NULL;
   1683     }
   1684 
   1685     if (EVP_PKEY_print_private(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) {
   1686         throwExceptionIfNecessary(env, "EVP_PKEY_print_private");
   1687         return NULL;
   1688     }
   1689     // Null terminate this
   1690     BIO_write(buffer.get(), "\0", 1);
   1691 
   1692     char *tmp;
   1693     BIO_get_mem_data(buffer.get(), &tmp);
   1694     jstring description = env->NewStringUTF(tmp);
   1695 
   1696     JNI_TRACE("EVP_PKEY_print_private(%p) => \"%s\"", pkey, tmp);
   1697     return description;
   1698 }
   1699 
   1700 static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, jlong pkeyRef) {
   1701     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1702     JNI_TRACE("EVP_PKEY_free(%p)", pkey);
   1703 
   1704     if (pkey != NULL) {
   1705         EVP_PKEY_free(pkey);
   1706     }
   1707 }
   1708 
   1709 static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jlong pkey1Ref, jlong pkey2Ref) {
   1710     EVP_PKEY* pkey1 = reinterpret_cast<EVP_PKEY*>(pkey1Ref);
   1711     EVP_PKEY* pkey2 = reinterpret_cast<EVP_PKEY*>(pkey2Ref);
   1712     JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1, pkey2);
   1713 
   1714     if (pkey1 == NULL) {
   1715         JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey1 == NULL", pkey1, pkey2);
   1716         jniThrowNullPointerException(env, "pkey1 == NULL");
   1717         return -1;
   1718     } else if (pkey2 == NULL) {
   1719         JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey2 == NULL", pkey1, pkey2);
   1720         jniThrowNullPointerException(env, "pkey2 == NULL");
   1721         return -1;
   1722     }
   1723 
   1724     int result = EVP_PKEY_cmp(pkey1, pkey2);
   1725     JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result);
   1726     return result;
   1727 }
   1728 
   1729 /*
   1730  * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[])
   1731  */
   1732 static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jlong pkeyRef) {
   1733     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1734     JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey);
   1735 
   1736     if (pkey == NULL) {
   1737         jniThrowNullPointerException(env, NULL);
   1738         return NULL;
   1739     }
   1740 
   1741     Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey));
   1742     if (pkcs8.get() == NULL) {
   1743         throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO");
   1744         JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey);
   1745         return NULL;
   1746     }
   1747 
   1748     return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO>(env, pkcs8.get());
   1749 }
   1750 
   1751 /*
   1752  * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[])
   1753  */
   1754 static jlong NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
   1755     JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes);
   1756 
   1757     ScopedByteArrayRO bytes(env, keyJavaBytes);
   1758     if (bytes.get() == NULL) {
   1759         JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes);
   1760         return 0;
   1761     }
   1762 
   1763     const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
   1764     Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, bytes.size()));
   1765     if (pkcs8.get() == NULL) {
   1766         throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
   1767         JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes);
   1768         return 0;
   1769     }
   1770 
   1771     Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
   1772     if (pkey.get() == NULL) {
   1773         throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
   1774         JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes);
   1775         return 0;
   1776     }
   1777 
   1778     JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get());
   1779     return reinterpret_cast<uintptr_t>(pkey.release());
   1780 }
   1781 
   1782 /*
   1783  * static native byte[] i2d_PUBKEY(int)
   1784  */
   1785 static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jlong pkeyRef) {
   1786     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1787     JNI_TRACE("i2d_PUBKEY(%p)", pkey);
   1788     return ASN1ToByteArray<EVP_PKEY, i2d_PUBKEY>(env, pkey);
   1789 }
   1790 
   1791 /*
   1792  * static native int d2i_PUBKEY(byte[])
   1793  */
   1794 static jlong NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) {
   1795     JNI_TRACE("d2i_PUBKEY(%p)", javaBytes);
   1796 
   1797     ScopedByteArrayRO bytes(env, javaBytes);
   1798     if (bytes.get() == NULL) {
   1799         JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes);
   1800         return 0;
   1801     }
   1802 
   1803     const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
   1804     Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, bytes.size()));
   1805     if (pkey.get() == NULL) {
   1806         JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes);
   1807         throwExceptionIfNecessary(env, "d2i_PUBKEY");
   1808         return 0;
   1809     }
   1810 
   1811     return reinterpret_cast<uintptr_t>(pkey.release());
   1812 }
   1813 
   1814 /*
   1815  * public static native int RSA_generate_key(int modulusBits, byte[] publicExponent);
   1816  */
   1817 static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits,
   1818         jbyteArray publicExponent) {
   1819     JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent);
   1820 
   1821     BIGNUM* eRef;
   1822     if (!arrayToBignum(env, publicExponent, &eRef)) {
   1823         return 0;
   1824     }
   1825     Unique_BIGNUM e(eRef);
   1826 
   1827     Unique_RSA rsa(RSA_new());
   1828     if (rsa.get() == NULL) {
   1829         jniThrowOutOfMemory(env, "Unable to allocate RSA key");
   1830         return 0;
   1831     }
   1832 
   1833     if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), NULL) < 0) {
   1834         throwExceptionIfNecessary(env, "RSA_generate_key_ex");
   1835         return 0;
   1836     }
   1837 
   1838     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   1839     if (pkey.get() == NULL) {
   1840         jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
   1841         return 0;
   1842     }
   1843 
   1844     if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
   1845         jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
   1846         return 0;
   1847     }
   1848 
   1849     OWNERSHIP_TRANSFERRED(rsa);
   1850     JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get());
   1851     return reinterpret_cast<uintptr_t>(pkey.release());
   1852 }
   1853 
   1854 static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jlong pkeyRef) {
   1855     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1856     JNI_TRACE("RSA_size(%p)", pkey);
   1857 
   1858     Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
   1859     if (rsa.get() == NULL) {
   1860         jniThrowRuntimeException(env, "RSA_size failed");
   1861         return 0;
   1862     }
   1863 
   1864     return static_cast<jint>(RSA_size(rsa.get()));
   1865 }
   1866 
   1867 typedef int RSACryptOperation(int flen, const unsigned char* from, unsigned char* to, RSA* rsa,
   1868                               int padding);
   1869 
   1870 static jint RSA_crypt_operation(RSACryptOperation operation,
   1871         const char* caller __attribute__ ((unused)), JNIEnv* env, jint flen,
   1872         jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
   1873     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1874     JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey);
   1875 
   1876     Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
   1877     if (rsa.get() == NULL) {
   1878         return -1;
   1879     }
   1880 
   1881     ScopedByteArrayRO from(env, fromJavaBytes);
   1882     if (from.get() == NULL) {
   1883         return -1;
   1884     }
   1885 
   1886     ScopedByteArrayRW to(env, toJavaBytes);
   1887     if (to.get() == NULL) {
   1888         return -1;
   1889     }
   1890 
   1891     int resultSize = operation(static_cast<int>(flen),
   1892             reinterpret_cast<const unsigned char*>(from.get()),
   1893             reinterpret_cast<unsigned char*>(to.get()), rsa.get(), padding);
   1894     if (resultSize == -1) {
   1895         JNI_TRACE("%s => failed", caller);
   1896         throwExceptionIfNecessary(env, "RSA_crypt_operation");
   1897         return -1;
   1898     }
   1899 
   1900     JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey,
   1901               resultSize);
   1902     return static_cast<jint>(resultSize);
   1903 }
   1904 
   1905 static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen,
   1906         jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
   1907     return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__,
   1908                                env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
   1909 }
   1910 static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen,
   1911         jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
   1912     return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__,
   1913                                env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
   1914 }
   1915 static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen,
   1916         jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
   1917     return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__,
   1918                                env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
   1919 }
   1920 static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen,
   1921         jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jlong pkeyRef, jint padding) {
   1922     return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__,
   1923                                env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
   1924 }
   1925 
   1926 /*
   1927  * public static native byte[][] get_RSA_public_params(int);
   1928  */
   1929 static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jlong pkeyRef) {
   1930     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1931     JNI_TRACE("get_RSA_public_params(%p)", pkey);
   1932 
   1933     if (pkey == NULL) {
   1934         jniThrowNullPointerException(env, "pkey == null");
   1935         return 0;
   1936     }
   1937 
   1938     Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
   1939     if (rsa.get() == NULL) {
   1940         throwExceptionIfNecessary(env, "get_RSA_public_params failed");
   1941         return 0;
   1942     }
   1943 
   1944     jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL);
   1945     if (joa == NULL) {
   1946         return NULL;
   1947     }
   1948 
   1949     jbyteArray n = bignumToArray(env, rsa->n, "n");
   1950     if (env->ExceptionCheck()) {
   1951         return NULL;
   1952     }
   1953     env->SetObjectArrayElement(joa, 0, n);
   1954 
   1955     jbyteArray e = bignumToArray(env, rsa->e, "e");
   1956     if (env->ExceptionCheck()) {
   1957         return NULL;
   1958     }
   1959     env->SetObjectArrayElement(joa, 1, e);
   1960 
   1961     return joa;
   1962 }
   1963 
   1964 /*
   1965  * public static native byte[][] get_RSA_private_params(int);
   1966  */
   1967 static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jlong pkeyRef) {
   1968     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   1969     JNI_TRACE("get_RSA_public_params(%p)", pkey);
   1970 
   1971     if (pkey == NULL) {
   1972         jniThrowNullPointerException(env, "pkey == null");
   1973         return 0;
   1974     }
   1975 
   1976     Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
   1977     if (rsa.get() == NULL) {
   1978         throwExceptionIfNecessary(env, "get_RSA_public_params failed");
   1979         return 0;
   1980     }
   1981 
   1982     jobjectArray joa = env->NewObjectArray(8, byteArrayClass, NULL);
   1983     if (joa == NULL) {
   1984         return NULL;
   1985     }
   1986 
   1987     jbyteArray n = bignumToArray(env, rsa->n, "n");
   1988     if (env->ExceptionCheck()) {
   1989         return NULL;
   1990     }
   1991     env->SetObjectArrayElement(joa, 0, n);
   1992 
   1993     if (rsa->e != NULL) {
   1994         jbyteArray e = bignumToArray(env, rsa->e, "e");
   1995         if (env->ExceptionCheck()) {
   1996             return NULL;
   1997         }
   1998         env->SetObjectArrayElement(joa, 1, e);
   1999     }
   2000 
   2001     if (rsa->d != NULL) {
   2002         jbyteArray d = bignumToArray(env, rsa->d, "d");
   2003         if (env->ExceptionCheck()) {
   2004             return NULL;
   2005         }
   2006         env->SetObjectArrayElement(joa, 2, d);
   2007     }
   2008 
   2009     if (rsa->p != NULL) {
   2010         jbyteArray p = bignumToArray(env, rsa->p, "p");
   2011         if (env->ExceptionCheck()) {
   2012             return NULL;
   2013         }
   2014         env->SetObjectArrayElement(joa, 3, p);
   2015     }
   2016 
   2017     if (rsa->q != NULL) {
   2018         jbyteArray q = bignumToArray(env, rsa->q, "q");
   2019         if (env->ExceptionCheck()) {
   2020             return NULL;
   2021         }
   2022         env->SetObjectArrayElement(joa, 4, q);
   2023     }
   2024 
   2025     if (rsa->dmp1 != NULL) {
   2026         jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1");
   2027         if (env->ExceptionCheck()) {
   2028             return NULL;
   2029         }
   2030         env->SetObjectArrayElement(joa, 5, dmp1);
   2031     }
   2032 
   2033     if (rsa->dmq1 != NULL) {
   2034         jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1");
   2035         if (env->ExceptionCheck()) {
   2036             return NULL;
   2037         }
   2038         env->SetObjectArrayElement(joa, 6, dmq1);
   2039     }
   2040 
   2041     if (rsa->iqmp != NULL) {
   2042         jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp");
   2043         if (env->ExceptionCheck()) {
   2044             return NULL;
   2045         }
   2046         env->SetObjectArrayElement(joa, 7, iqmp);
   2047     }
   2048 
   2049     return joa;
   2050 }
   2051 
   2052 /*
   2053  * public static native int DSA_generate_key(int, byte[]);
   2054  */
   2055 static jlong NativeCrypto_DSA_generate_key(JNIEnv* env, jclass, jint primeBits,
   2056         jbyteArray seedJavaBytes, jbyteArray gBytes, jbyteArray pBytes, jbyteArray qBytes) {
   2057     JNI_TRACE("DSA_generate_key(%d, %p, %p, %p, %p)", primeBits, seedJavaBytes,
   2058             gBytes, pBytes, qBytes);
   2059 
   2060     UniquePtr<unsigned char[]> seedPtr;
   2061     unsigned long seedSize = 0;
   2062     if (seedJavaBytes != NULL) {
   2063         ScopedByteArrayRO seed(env, seedJavaBytes);
   2064         if (seed.get() == NULL) {
   2065             return 0;
   2066         }
   2067 
   2068         seedSize = seed.size();
   2069         seedPtr.reset(new unsigned char[seedSize]);
   2070 
   2071         memcpy(seedPtr.get(), seed.get(), seedSize);
   2072     }
   2073 
   2074     Unique_DSA dsa(DSA_new());
   2075     if (dsa.get() == NULL) {
   2076         JNI_TRACE("DSA_generate_key failed");
   2077         jniThrowOutOfMemory(env, "Unable to allocate DSA key");
   2078         freeOpenSslErrorState();
   2079         return 0;
   2080     }
   2081 
   2082     if (gBytes != NULL && pBytes != NULL && qBytes != NULL) {
   2083         JNI_TRACE("DSA_generate_key parameters specified");
   2084 
   2085         if (!arrayToBignum(env, gBytes, &dsa->g)) {
   2086             return 0;
   2087         }
   2088 
   2089         if (!arrayToBignum(env, pBytes, &dsa->p)) {
   2090             return 0;
   2091         }
   2092 
   2093         if (!arrayToBignum(env, qBytes, &dsa->q)) {
   2094             return 0;
   2095         }
   2096     } else {
   2097         JNI_TRACE("DSA_generate_key generating parameters");
   2098 
   2099         if (!DSA_generate_parameters_ex(dsa.get(), primeBits, seedPtr.get(), seedSize, NULL, NULL, NULL)) {
   2100             JNI_TRACE("DSA_generate_key => param generation failed");
   2101             throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_parameters_ex failed");
   2102             return 0;
   2103         }
   2104     }
   2105 
   2106     if (!DSA_generate_key(dsa.get())) {
   2107         JNI_TRACE("DSA_generate_key failed");
   2108         throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed");
   2109         return 0;
   2110     }
   2111 
   2112     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   2113     if (pkey.get() == NULL) {
   2114         JNI_TRACE("DSA_generate_key failed");
   2115         jniThrowRuntimeException(env, "NativeCrypto_DSA_generate_key failed");
   2116         freeOpenSslErrorState();
   2117         return 0;
   2118     }
   2119 
   2120     if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
   2121         JNI_TRACE("DSA_generate_key failed");
   2122         throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed");
   2123         return 0;
   2124     }
   2125 
   2126     OWNERSHIP_TRANSFERRED(dsa);
   2127     JNI_TRACE("DSA_generate_key(n=%d, e=%p) => %p", primeBits, seedPtr.get(), pkey.get());
   2128     return reinterpret_cast<uintptr_t>(pkey.release());
   2129 }
   2130 
   2131 /*
   2132  * public static native byte[][] get_DSA_params(int);
   2133  */
   2134 static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jlong pkeyRef) {
   2135     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   2136     JNI_TRACE("get_DSA_params(%p)", pkey);
   2137 
   2138     Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey));
   2139     if (dsa.get() == NULL) {
   2140         throwExceptionIfNecessary(env, "get_DSA_params failed");
   2141         return 0;
   2142     }
   2143 
   2144     jobjectArray joa = env->NewObjectArray(5, byteArrayClass, NULL);
   2145     if (joa == NULL) {
   2146         return NULL;
   2147     }
   2148 
   2149     if (dsa->g != NULL) {
   2150         jbyteArray g = bignumToArray(env, dsa->g, "g");
   2151         if (env->ExceptionCheck()) {
   2152             return NULL;
   2153         }
   2154         env->SetObjectArrayElement(joa, 0, g);
   2155     }
   2156 
   2157     if (dsa->p != NULL) {
   2158         jbyteArray p = bignumToArray(env, dsa->p, "p");
   2159         if (env->ExceptionCheck()) {
   2160             return NULL;
   2161         }
   2162         env->SetObjectArrayElement(joa, 1, p);
   2163     }
   2164 
   2165     if (dsa->q != NULL) {
   2166         jbyteArray q = bignumToArray(env, dsa->q, "q");
   2167         if (env->ExceptionCheck()) {
   2168             return NULL;
   2169         }
   2170         env->SetObjectArrayElement(joa, 2, q);
   2171     }
   2172 
   2173     if (dsa->pub_key != NULL) {
   2174         jbyteArray pub_key = bignumToArray(env, dsa->pub_key, "pub_key");
   2175         if (env->ExceptionCheck()) {
   2176             return NULL;
   2177         }
   2178         env->SetObjectArrayElement(joa, 3, pub_key);
   2179     }
   2180 
   2181     if (dsa->priv_key != NULL) {
   2182         jbyteArray priv_key = bignumToArray(env, dsa->priv_key, "priv_key");
   2183         if (env->ExceptionCheck()) {
   2184             return NULL;
   2185         }
   2186         env->SetObjectArrayElement(joa, 4, priv_key);
   2187     }
   2188 
   2189     return joa;
   2190 }
   2191 
   2192 #define EC_CURVE_GFP 1
   2193 #define EC_CURVE_GF2M 2
   2194 
   2195 /**
   2196  * Return group type or 0 if unknown group.
   2197  * EC_GROUP_GFP or EC_GROUP_GF2M
   2198  */
   2199 static int get_EC_GROUP_type(const EC_GROUP* group)
   2200 {
   2201     const EC_METHOD* method = EC_GROUP_method_of(group);
   2202     if (method == EC_GFp_nist_method()
   2203                 || method == EC_GFp_mont_method()
   2204                 || method == EC_GFp_simple_method()) {
   2205         return EC_CURVE_GFP;
   2206     } else if (method == EC_GF2m_simple_method()) {
   2207         return EC_CURVE_GF2M;
   2208     }
   2209 
   2210     return 0;
   2211 }
   2212 
   2213 static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava)
   2214 {
   2215     JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava);
   2216 
   2217     ScopedUtfChars curveName(env, curveNameJava);
   2218     if (curveName.c_str() == NULL) {
   2219         return 0;
   2220     }
   2221     JNI_TRACE("EC_GROUP_new_by_curve_name(%s)", curveName.c_str());
   2222 
   2223     int nid = OBJ_sn2nid(curveName.c_str());
   2224     if (nid == NID_undef) {
   2225         JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID name", curveName.c_str());
   2226         return 0;
   2227     }
   2228 
   2229     EC_GROUP* group = EC_GROUP_new_by_curve_name(nid);
   2230     if (group == NULL) {
   2231         JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID %d", curveName.c_str(), nid);
   2232         freeOpenSslErrorState();
   2233         return 0;
   2234     }
   2235 
   2236     JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => %p", curveName.c_str(), group);
   2237     return reinterpret_cast<uintptr_t>(group);
   2238 }
   2239 
   2240 static void NativeCrypto_EC_GROUP_set_asn1_flag(JNIEnv* env, jclass, jlong groupRef,
   2241         jint flag)
   2242 {
   2243     EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
   2244     JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d)", group, flag);
   2245 
   2246     if (group == NULL) {
   2247         JNI_TRACE("EC_GROUP_set_asn1_flag => group == NULL");
   2248         jniThrowNullPointerException(env, "group == NULL");
   2249         return;
   2250     }
   2251 
   2252     EC_GROUP_set_asn1_flag(group, flag);
   2253     JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d) => success", group, flag);
   2254 }
   2255 
   2256 static void NativeCrypto_EC_GROUP_set_point_conversion_form(JNIEnv* env, jclass,
   2257         jlong groupRef, jint form)
   2258 {
   2259     EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
   2260     JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d)", group, form);
   2261 
   2262     if (group == NULL) {
   2263         JNI_TRACE("EC_GROUP_set_point_conversion_form => group == NULL");
   2264         jniThrowNullPointerException(env, "group == NULL");
   2265         return;
   2266     }
   2267 
   2268     EC_GROUP_set_point_conversion_form(group, static_cast<point_conversion_form_t>(form));
   2269     JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d) => success", group, form);
   2270 }
   2271 
   2272 static jlong NativeCrypto_EC_GROUP_new_curve(JNIEnv* env, jclass, jint type, jbyteArray pJava,
   2273         jbyteArray aJava, jbyteArray bJava)
   2274 {
   2275     JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p)", type, pJava, aJava, bJava);
   2276 
   2277     BIGNUM* pRef;
   2278     if (!arrayToBignum(env, pJava, &pRef)) {
   2279         return 0;
   2280     }
   2281     Unique_BIGNUM p(pRef);
   2282 
   2283     BIGNUM* aRef;
   2284     if (!arrayToBignum(env, aJava, &aRef)) {
   2285         return 0;
   2286     }
   2287     Unique_BIGNUM a(aRef);
   2288 
   2289     BIGNUM* bRef;
   2290     if (!arrayToBignum(env, bJava, &bRef)) {
   2291         return 0;
   2292     }
   2293     Unique_BIGNUM b(bRef);
   2294 
   2295     EC_GROUP* group;
   2296     switch (type) {
   2297     case EC_CURVE_GFP:
   2298         group = EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), (BN_CTX*) NULL);
   2299         break;
   2300     case EC_CURVE_GF2M:
   2301         group = EC_GROUP_new_curve_GF2m(p.get(), a.get(), b.get(), (BN_CTX*) NULL);
   2302         break;
   2303     default:
   2304         jniThrowRuntimeException(env, "invalid group");
   2305         return 0;
   2306     }
   2307 
   2308     if (group == NULL) {
   2309         throwExceptionIfNecessary(env, "EC_GROUP_new_curve");
   2310     }
   2311 
   2312     JNI_TRACE("EC_GROUP_new_curve(%d, %p, %p, %p) => %p", type, pJava, aJava, bJava, group);
   2313     return reinterpret_cast<uintptr_t>(group);
   2314 }
   2315 
   2316 static jlong NativeCrypto_EC_GROUP_dup(JNIEnv* env, jclass, jlong groupRef) {
   2317     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2318     JNI_TRACE("EC_GROUP_dup(%p)", group);
   2319 
   2320     if (group == NULL) {
   2321          JNI_TRACE("EC_GROUP_dup => group == NULL");
   2322          jniThrowNullPointerException(env, "group == NULL");
   2323          return 0;
   2324      }
   2325 
   2326      EC_GROUP* groupDup = EC_GROUP_dup(group);
   2327      JNI_TRACE("EC_GROUP_dup(%p) => %p", group, groupDup);
   2328      return reinterpret_cast<uintptr_t>(groupDup);
   2329 }
   2330 
   2331 static jstring NativeCrypto_EC_GROUP_get_curve_name(JNIEnv* env, jclass, jlong groupRef) {
   2332     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2333     JNI_TRACE("EC_GROUP_get_curve_name(%p)", group);
   2334 
   2335     if (group == NULL) {
   2336         JNI_TRACE("EC_GROUP_get_curve_name => group == NULL");
   2337         jniThrowNullPointerException(env, "group == NULL");
   2338         return 0;
   2339     }
   2340 
   2341     int nid = EC_GROUP_get_curve_name(group);
   2342     if (nid == NID_undef) {
   2343         JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group);
   2344         return NULL;
   2345     }
   2346 
   2347     const char* shortName = OBJ_nid2sn(nid);
   2348     JNI_TRACE("EC_GROUP_get_curve_name(%p) => \"%s\"", group, shortName);
   2349     return env->NewStringUTF(shortName);
   2350 }
   2351 
   2352 static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jlong groupRef)
   2353 {
   2354     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2355     JNI_TRACE("EC_GROUP_get_curve(%p)", group);
   2356 
   2357     Unique_BIGNUM p(BN_new());
   2358     Unique_BIGNUM a(BN_new());
   2359     Unique_BIGNUM b(BN_new());
   2360 
   2361     int ret;
   2362     switch (get_EC_GROUP_type(group)) {
   2363     case EC_CURVE_GFP:
   2364         ret = EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), (BN_CTX*) NULL);
   2365         break;
   2366     case EC_CURVE_GF2M:
   2367         ret = EC_GROUP_get_curve_GF2m(group, p.get(), a.get(), b.get(), (BN_CTX*)NULL);
   2368         break;
   2369     default:
   2370         jniThrowRuntimeException(env, "invalid group");
   2371         return NULL;
   2372     }
   2373     if (ret != 1) {
   2374         throwExceptionIfNecessary(env, "EC_GROUP_get_curve");
   2375         return NULL;
   2376     }
   2377 
   2378     jobjectArray joa = env->NewObjectArray(3, byteArrayClass, NULL);
   2379     if (joa == NULL) {
   2380         return NULL;
   2381     }
   2382 
   2383     jbyteArray pArray = bignumToArray(env, p.get(), "p");
   2384     if (env->ExceptionCheck()) {
   2385         return NULL;
   2386     }
   2387     env->SetObjectArrayElement(joa, 0, pArray);
   2388 
   2389     jbyteArray aArray = bignumToArray(env, a.get(), "a");
   2390     if (env->ExceptionCheck()) {
   2391         return NULL;
   2392     }
   2393     env->SetObjectArrayElement(joa, 1, aArray);
   2394 
   2395     jbyteArray bArray = bignumToArray(env, b.get(), "b");
   2396     if (env->ExceptionCheck()) {
   2397         return NULL;
   2398     }
   2399     env->SetObjectArrayElement(joa, 2, bArray);
   2400 
   2401     JNI_TRACE("EC_GROUP_get_curve(%p) => %p", group, joa);
   2402     return joa;
   2403 }
   2404 
   2405 static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jlong groupRef)
   2406 {
   2407     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2408     JNI_TRACE("EC_GROUP_get_order(%p)", group);
   2409 
   2410     Unique_BIGNUM order(BN_new());
   2411     if (order.get() == NULL) {
   2412         JNI_TRACE("EC_GROUP_get_order(%p) => can't create BN", group);
   2413         jniThrowOutOfMemory(env, "BN_new");
   2414         return NULL;
   2415     }
   2416 
   2417     if (EC_GROUP_get_order(group, order.get(), NULL) != 1) {
   2418         JNI_TRACE("EC_GROUP_get_order(%p) => threw error", group);
   2419         throwExceptionIfNecessary(env, "EC_GROUP_get_order");
   2420         return NULL;
   2421     }
   2422 
   2423     jbyteArray orderArray = bignumToArray(env, order.get(), "order");
   2424     if (env->ExceptionCheck()) {
   2425         return NULL;
   2426     }
   2427 
   2428     JNI_TRACE("EC_GROUP_get_order(%p) => %p", group, orderArray);
   2429     return orderArray;
   2430 }
   2431 
   2432 static jint NativeCrypto_EC_GROUP_get_degree(JNIEnv* env, jclass, jlong groupRef)
   2433 {
   2434     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2435     JNI_TRACE("EC_GROUP_get_degree(%p)", group);
   2436 
   2437     jint degree = EC_GROUP_get_degree(group);
   2438     if (degree == 0) {
   2439       JNI_TRACE("EC_GROUP_get_degree(%p) => unsupported", group);
   2440       jniThrowRuntimeException(env, "not supported");
   2441       return 0;
   2442     }
   2443 
   2444     JNI_TRACE("EC_GROUP_get_degree(%p) => %d", group, degree);
   2445     return degree;
   2446 }
   2447 
   2448 static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jlong groupRef)
   2449 {
   2450     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2451     JNI_TRACE("EC_GROUP_get_cofactor(%p)", group);
   2452 
   2453     Unique_BIGNUM cofactor(BN_new());
   2454     if (cofactor.get() == NULL) {
   2455         JNI_TRACE("EC_GROUP_get_cofactor(%p) => can't create BN", group);
   2456         jniThrowOutOfMemory(env, "BN_new");
   2457         return NULL;
   2458     }
   2459 
   2460     if (EC_GROUP_get_cofactor(group, cofactor.get(), NULL) != 1) {
   2461         JNI_TRACE("EC_GROUP_get_cofactor(%p) => threw error", group);
   2462         throwExceptionIfNecessary(env, "EC_GROUP_get_cofactor");
   2463         return NULL;
   2464     }
   2465 
   2466     jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor");
   2467     if (env->ExceptionCheck()) {
   2468         return NULL;
   2469     }
   2470 
   2471     JNI_TRACE("EC_GROUP_get_cofactor(%p) => %p", group, cofactorArray);
   2472     return cofactorArray;
   2473 }
   2474 
   2475 static jint NativeCrypto_get_EC_GROUP_type(JNIEnv* env, jclass, jlong groupRef)
   2476 {
   2477     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2478     JNI_TRACE("get_EC_GROUP_type(%p)", group);
   2479 
   2480     int type = get_EC_GROUP_type(group);
   2481     if (type == 0) {
   2482         JNI_TRACE("get_EC_GROUP_type(%p) => curve type", group);
   2483         jniThrowRuntimeException(env, "unknown curve type");
   2484     } else {
   2485         JNI_TRACE("get_EC_GROUP_type(%p) => %d", group, type);
   2486     }
   2487     return type;
   2488 }
   2489 
   2490 static void NativeCrypto_EC_GROUP_clear_free(JNIEnv* env, jclass, jlong groupRef)
   2491 {
   2492     EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
   2493     JNI_TRACE("EC_GROUP_clear_free(%p)", group);
   2494 
   2495     if (group == NULL) {
   2496         JNI_TRACE("EC_GROUP_clear_free => group == NULL");
   2497         jniThrowNullPointerException(env, "group == NULL");
   2498         return;
   2499     }
   2500 
   2501     EC_GROUP_clear_free(group);
   2502     JNI_TRACE("EC_GROUP_clear_free(%p) => success", group);
   2503 }
   2504 
   2505 static jboolean NativeCrypto_EC_GROUP_cmp(JNIEnv* env, jclass, jlong group1Ref, jlong group2Ref)
   2506 {
   2507     const EC_GROUP* group1 = reinterpret_cast<const EC_GROUP*>(group1Ref);
   2508     const EC_GROUP* group2 = reinterpret_cast<const EC_GROUP*>(group2Ref);
   2509     JNI_TRACE("EC_GROUP_cmp(%p, %p)", group1, group2);
   2510 
   2511     if (group1 == NULL || group2 == NULL) {
   2512         JNI_TRACE("EC_GROUP_cmp(%p, %p) => group1 == null || group2 == null", group1, group2);
   2513         jniThrowNullPointerException(env, "group1 == null || group2 == null");
   2514         return false;
   2515     }
   2516 
   2517     int ret = EC_GROUP_cmp(group1, group2, (BN_CTX*)NULL);
   2518 
   2519     JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", group1, group2, ret);
   2520     return ret == 0;
   2521 }
   2522 
   2523 static void NativeCrypto_EC_GROUP_set_generator(JNIEnv* env, jclass, jlong groupRef, jlong pointRef, jbyteArray njavaBytes, jbyteArray hjavaBytes)
   2524 {
   2525     EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef);
   2526     const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef);
   2527     JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p)", group, point, njavaBytes, hjavaBytes);
   2528 
   2529     if (group == NULL || point == NULL) {
   2530         JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => group == null || point == null",
   2531                 group, point, njavaBytes, hjavaBytes);
   2532         jniThrowNullPointerException(env, "group == null || point == null");
   2533         return;
   2534     }
   2535 
   2536     BIGNUM* nRef;
   2537     if (!arrayToBignum(env, njavaBytes, &nRef)) {
   2538         return;
   2539     }
   2540     Unique_BIGNUM n(nRef);
   2541 
   2542     BIGNUM* hRef;
   2543     if (!arrayToBignum(env, hjavaBytes, &hRef)) {
   2544         return;
   2545     }
   2546     Unique_BIGNUM h(hRef);
   2547 
   2548     int ret = EC_GROUP_set_generator(group, point, n.get(), h.get());
   2549     if (ret == 0) {
   2550         throwExceptionIfNecessary(env, "EC_GROUP_set_generator");
   2551     }
   2552 
   2553     JNI_TRACE("EC_GROUP_set_generator(%p, %p, %p, %p) => %d", group, point, njavaBytes, hjavaBytes, ret);
   2554 }
   2555 
   2556 static jlong NativeCrypto_EC_GROUP_get_generator(JNIEnv* env, jclass, jlong groupRef)
   2557 {
   2558     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2559     JNI_TRACE("EC_GROUP_get_generator(%p)", group);
   2560 
   2561     if (group == NULL) {
   2562         JNI_TRACE("EC_POINT_get_generator(%p) => group == null", group);
   2563         jniThrowNullPointerException(env, "group == null");
   2564         return 0;
   2565     }
   2566 
   2567     const EC_POINT* generator = EC_GROUP_get0_generator(group);
   2568 
   2569     Unique_EC_POINT dup(EC_POINT_dup(generator, group));
   2570     if (dup.get() == NULL) {
   2571         JNI_TRACE("EC_GROUP_get_generator(%p) => oom error", group);
   2572         jniThrowOutOfMemory(env, "unable to dupe generator");
   2573         return 0;
   2574     }
   2575 
   2576     JNI_TRACE("EC_GROUP_get_generator(%p) => %p", group, dup.get());
   2577     return reinterpret_cast<uintptr_t>(dup.release());
   2578 }
   2579 
   2580 static jlong NativeCrypto_EC_POINT_new(JNIEnv* env, jclass, jlong groupRef)
   2581 {
   2582     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2583     JNI_TRACE("EC_POINT_new(%p)", group);
   2584 
   2585     if (group == NULL) {
   2586         JNI_TRACE("EC_POINT_new(%p) => group == null", group);
   2587         jniThrowNullPointerException(env, "group == null");
   2588         return 0;
   2589     }
   2590 
   2591     EC_POINT* point = EC_POINT_new(group);
   2592     if (point == NULL) {
   2593         jniThrowOutOfMemory(env, "Unable create an EC_POINT");
   2594         return 0;
   2595     }
   2596 
   2597     return reinterpret_cast<uintptr_t>(point);
   2598 }
   2599 
   2600 static void NativeCrypto_EC_POINT_clear_free(JNIEnv* env, jclass, jlong groupRef) {
   2601     EC_POINT* group = reinterpret_cast<EC_POINT*>(groupRef);
   2602     JNI_TRACE("EC_POINT_clear_free(%p)", group);
   2603 
   2604     if (group == NULL) {
   2605         JNI_TRACE("EC_POINT_clear_free => group == NULL");
   2606         jniThrowNullPointerException(env, "group == NULL");
   2607         return;
   2608     }
   2609 
   2610     EC_POINT_clear_free(group);
   2611     JNI_TRACE("EC_POINT_clear_free(%p) => success", group);
   2612 }
   2613 
   2614 static jboolean NativeCrypto_EC_POINT_cmp(JNIEnv* env, jclass, jlong groupRef, jlong point1Ref, jlong point2Ref)
   2615 {
   2616     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2617     const EC_POINT* point1 = reinterpret_cast<const EC_POINT*>(point1Ref);
   2618     const EC_POINT* point2 = reinterpret_cast<const EC_POINT*>(point2Ref);
   2619     JNI_TRACE("EC_POINT_cmp(%p, %p, %p)", group, point1, point2);
   2620 
   2621     if (group == NULL || point1 == NULL || point2 == NULL) {
   2622         JNI_TRACE("EC_POINT_cmp(%p, %p, %p) => group == null || point1 == null || point2 == null",
   2623                 group, point1, point2);
   2624         jniThrowNullPointerException(env, "group == null || point1 == null || point2 == null");
   2625         return false;
   2626     }
   2627 
   2628     int ret = EC_POINT_cmp(group, point1, point2, (BN_CTX*)NULL);
   2629 
   2630     JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", point1, point2, ret);
   2631     return ret == 0;
   2632 }
   2633 
   2634 static void NativeCrypto_EC_POINT_set_affine_coordinates(JNIEnv* env, jclass,
   2635         jlong groupRef, jlong pointRef, jbyteArray xjavaBytes, jbyteArray yjavaBytes)
   2636 {
   2637     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2638     EC_POINT* point = reinterpret_cast<EC_POINT*>(pointRef);
   2639     JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p)", group, point, xjavaBytes,
   2640             yjavaBytes);
   2641 
   2642     if (group == NULL || point == NULL) {
   2643         JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => group == null || point == null",
   2644                 group, point, xjavaBytes, yjavaBytes);
   2645         jniThrowNullPointerException(env, "group == null || point == null");
   2646         return;
   2647     }
   2648 
   2649     BIGNUM* xRef;
   2650     if (!arrayToBignum(env, xjavaBytes, &xRef)) {
   2651         return;
   2652     }
   2653     Unique_BIGNUM x(xRef);
   2654 
   2655     BIGNUM* yRef;
   2656     if (!arrayToBignum(env, yjavaBytes, &yRef)) {
   2657         return;
   2658     }
   2659     Unique_BIGNUM y(yRef);
   2660 
   2661     int ret;
   2662     switch (get_EC_GROUP_type(group)) {
   2663     case EC_CURVE_GFP:
   2664         ret = EC_POINT_set_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL);
   2665         break;
   2666     case EC_CURVE_GF2M:
   2667         ret = EC_POINT_set_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL);
   2668         break;
   2669     default:
   2670         jniThrowRuntimeException(env, "invalid curve type");
   2671         return;
   2672     }
   2673 
   2674     if (ret != 1) {
   2675         throwExceptionIfNecessary(env, "EC_POINT_set_affine_coordinates");
   2676     }
   2677 
   2678     JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => %d", group, point,
   2679             xjavaBytes, yjavaBytes, ret);
   2680 }
   2681 
   2682 static jobjectArray NativeCrypto_EC_POINT_get_affine_coordinates(JNIEnv* env, jclass, jlong groupRef,
   2683         jlong pointRef)
   2684 {
   2685     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2686     const EC_POINT* point = reinterpret_cast<const EC_POINT*>(pointRef);
   2687     JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point);
   2688 
   2689     Unique_BIGNUM x(BN_new());
   2690     Unique_BIGNUM y(BN_new());
   2691 
   2692     int ret;
   2693     switch (get_EC_GROUP_type(group)) {
   2694     case EC_CURVE_GFP:
   2695         ret = EC_POINT_get_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL);
   2696         break;
   2697     case EC_CURVE_GF2M:
   2698         ret = EC_POINT_get_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL);
   2699         break;
   2700     default:
   2701         jniThrowRuntimeException(env, "invalid curve type");
   2702         return NULL;
   2703     }
   2704     if (ret != 1) {
   2705         JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point);
   2706         throwExceptionIfNecessary(env, "EC_POINT_get_affine_coordinates");
   2707         return NULL;
   2708     }
   2709 
   2710     jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL);
   2711     if (joa == NULL) {
   2712         return NULL;
   2713     }
   2714 
   2715     jbyteArray xBytes = bignumToArray(env, x.get(), "x");
   2716     if (env->ExceptionCheck()) {
   2717         return NULL;
   2718     }
   2719     env->SetObjectArrayElement(joa, 0, xBytes);
   2720 
   2721     jbyteArray yBytes = bignumToArray(env, y.get(), "y");
   2722     if (env->ExceptionCheck()) {
   2723         return NULL;
   2724     }
   2725     env->SetObjectArrayElement(joa, 1, yBytes);
   2726 
   2727     JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p) => %p", group, point, joa);
   2728     return joa;
   2729 }
   2730 
   2731 static jlong NativeCrypto_EC_KEY_generate_key(JNIEnv* env, jclass, jlong groupRef)
   2732 {
   2733     const EC_GROUP* group = reinterpret_cast<const EC_GROUP*>(groupRef);
   2734     JNI_TRACE("EC_KEY_generate_key(%p)", group);
   2735 
   2736     Unique_EC_KEY eckey(EC_KEY_new());
   2737     if (eckey.get() == NULL) {
   2738         JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_new() oom", group);
   2739         jniThrowOutOfMemory(env, "Unable to create an EC_KEY");
   2740         return 0;
   2741     }
   2742 
   2743     if (EC_KEY_set_group(eckey.get(), group) != 1) {
   2744         JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_set_group error", group);
   2745         throwExceptionIfNecessary(env, "EC_KEY_set_group");
   2746         return 0;
   2747     }
   2748 
   2749     if (EC_KEY_generate_key(eckey.get()) != 1) {
   2750         JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_generate_key error", group);
   2751         throwExceptionIfNecessary(env, "EC_KEY_set_group");
   2752         return 0;
   2753     }
   2754 
   2755     Unique_EVP_PKEY pkey(EVP_PKEY_new());
   2756     if (pkey.get() == NULL) {
   2757         JNI_TRACE("EC_KEY_generate_key(%p) => threw error", group);
   2758         throwExceptionIfNecessary(env, "EC_KEY_generate_key");
   2759         return 0;
   2760     }
   2761     if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
   2762         jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
   2763         return 0;
   2764     }
   2765     OWNERSHIP_TRANSFERRED(eckey);
   2766 
   2767     JNI_TRACE("EC_KEY_generate_key(%p) => %p", group, pkey.get());
   2768     return reinterpret_cast<uintptr_t>(pkey.release());
   2769 }
   2770 
   2771 static jlong NativeCrypto_EC_KEY_get0_group(JNIEnv* env, jclass, jlong pkeyRef)
   2772 {
   2773     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   2774     JNI_TRACE("EC_KEY_get0_group(%p)", pkey);
   2775 
   2776     if (pkey == NULL) {
   2777         jniThrowNullPointerException(env, "pkey == null");
   2778         JNI_TRACE("EC_KEY_get0_group(%p) => pkey == null", pkey);
   2779         return 0;
   2780     }
   2781 
   2782     if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
   2783         jniThrowRuntimeException(env, "not EC key");
   2784         JNI_TRACE("EC_KEY_get0_group(%p) => not EC key (type == %d)", pkey,
   2785                 EVP_PKEY_type(pkey->type));
   2786         return 0;
   2787     }
   2788 
   2789     const EC_GROUP* group = EC_KEY_get0_group(pkey->pkey.ec);
   2790     JNI_TRACE("EC_KEY_get0_group(%p) => %p", pkey, group);
   2791     return reinterpret_cast<uintptr_t>(group);
   2792 }
   2793 
   2794 static jbyteArray NativeCrypto_EC_KEY_get_private_key(JNIEnv* env, jclass, jlong pkeyRef)
   2795 {
   2796     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   2797     JNI_TRACE("EC_KEY_get_private_key(%p)", pkey);
   2798 
   2799     Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
   2800     if (eckey.get() == NULL) {
   2801         throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY");
   2802         return NULL;
   2803     }
   2804 
   2805     const BIGNUM *privkey = EC_KEY_get0_private_key(eckey.get());
   2806 
   2807     jbyteArray privBytes = bignumToArray(env, privkey, "privkey");
   2808     if (env->ExceptionCheck()) {
   2809         JNI_TRACE("EC_KEY_get_private_key(%p) => threw error", pkey);
   2810         return NULL;
   2811     }
   2812 
   2813     JNI_TRACE("EC_KEY_get_private_key(%p) => %p", pkey, privBytes);
   2814     return privBytes;
   2815 }
   2816 
   2817 static jlong NativeCrypto_EC_KEY_get_public_key(JNIEnv* env, jclass, jlong pkeyRef)
   2818 {
   2819     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   2820     JNI_TRACE("EC_KEY_get_public_key(%p)", pkey);
   2821 
   2822     Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
   2823     if (eckey.get() == NULL) {
   2824         throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY");
   2825         return 0;
   2826     }
   2827 
   2828     Unique_EC_POINT dup(EC_POINT_dup(EC_KEY_get0_public_key(eckey.get()),
   2829             EC_KEY_get0_group(eckey.get())));
   2830     if (dup.get() == NULL) {
   2831         JNI_TRACE("EC_KEY_get_public_key(%p) => can't dup public key", pkey);
   2832         jniThrowRuntimeException(env, "EC_POINT_dup");
   2833         return 0;
   2834     }
   2835 
   2836     JNI_TRACE("EC_KEY_get_public_key(%p) => %p", pkey, dup.get());
   2837     return reinterpret_cast<uintptr_t>(dup.release());
   2838 }
   2839 
   2840 static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass,
   2841      jbyteArray outArray, jint outOffset, jlong pubkeyRef, jlong privkeyRef)
   2842 {
   2843     EVP_PKEY* pubPkey = reinterpret_cast<EVP_PKEY*>(pubkeyRef);
   2844     EVP_PKEY* privPkey = reinterpret_cast<EVP_PKEY*>(privkeyRef);
   2845     JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p)", outArray, outOffset, pubPkey, privPkey);
   2846 
   2847     ScopedByteArrayRW out(env, outArray);
   2848     if (out.get() == NULL) {
   2849         JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p) can't get output buffer",
   2850                 outArray, outOffset, pubPkey, privPkey);
   2851         return -1;
   2852     }
   2853 
   2854     if ((outOffset < 0) || ((size_t) outOffset >= out.size())) {
   2855         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
   2856         return -1;
   2857     }
   2858 
   2859     Unique_EC_KEY pubkey(EVP_PKEY_get1_EC_KEY(pubPkey));
   2860     if (pubkey.get() == NULL) {
   2861         JNI_TRACE("ECDH_compute_key(%p) => can't get public key", pubPkey);
   2862         throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public");
   2863         return -1;
   2864     }
   2865 
   2866     const EC_POINT* pubkeyPoint = EC_KEY_get0_public_key(pubkey.get());
   2867     if (pubkeyPoint == NULL) {
   2868         JNI_TRACE("ECDH_compute_key(%p) => can't get public key point", pubPkey);
   2869         throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public");
   2870         return -1;
   2871     }
   2872 
   2873     Unique_EC_KEY privkey(EVP_PKEY_get1_EC_KEY(privPkey));
   2874     if (privkey.get() == NULL) {
   2875         throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY private");
   2876         return -1;
   2877     }
   2878 
   2879     int outputLength = ECDH_compute_key(
   2880             &out[outOffset],
   2881             out.size() - outOffset,
   2882             pubkeyPoint,
   2883             privkey.get(),
   2884             NULL // No KDF
   2885             );
   2886     if (outputLength == -1) {
   2887         throwExceptionIfNecessary(env, "ECDH_compute_key");
   2888         return -1;
   2889     }
   2890 
   2891     return outputLength;
   2892 }
   2893 
   2894 static jlong NativeCrypto_EVP_MD_CTX_create(JNIEnv* env, jclass) {
   2895     JNI_TRACE("EVP_MD_CTX_create()");
   2896 
   2897     Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
   2898     if (ctx.get() == NULL) {
   2899         jniThrowOutOfMemory(env, "Unable create a EVP_MD_CTX");
   2900         return 0;
   2901     }
   2902 
   2903     JNI_TRACE("EVP_MD_CTX_create() => %p", ctx.get());
   2904     return reinterpret_cast<uintptr_t>(ctx.release());
   2905 }
   2906 
   2907 static void NativeCrypto_EVP_MD_CTX_init(JNIEnv*, jclass, jlong ctxRef) {
   2908     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   2909     JNI_TRACE("NativeCrypto_EVP_MD_CTX_init(%p)", ctx);
   2910 
   2911     if (ctx != NULL) {
   2912         EVP_MD_CTX_init(ctx);
   2913     }
   2914 }
   2915 
   2916 static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, jlong ctxRef) {
   2917     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   2918     JNI_TRACE("NativeCrypto_EVP_MD_CTX_destroy(%p)", ctx);
   2919 
   2920     if (ctx != NULL) {
   2921         EVP_MD_CTX_destroy(ctx);
   2922     }
   2923 }
   2924 
   2925 static jlong NativeCrypto_EVP_MD_CTX_copy(JNIEnv* env, jclass, jlong ctxRef) {
   2926     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   2927     JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p)", ctx);
   2928 
   2929     if (ctx == NULL) {
   2930         jniThrowNullPointerException(env, "ctx == null");
   2931         return 0;
   2932     }
   2933 
   2934     EVP_MD_CTX* copy = EVP_MD_CTX_create();
   2935     if (copy == NULL) {
   2936         jniThrowOutOfMemory(env, "Unable to allocate copy of EVP_MD_CTX");
   2937         return 0;
   2938     }
   2939 
   2940     EVP_MD_CTX_init(copy);
   2941     int result = EVP_MD_CTX_copy_ex(copy, ctx);
   2942     if (result == 0) {
   2943         EVP_MD_CTX_destroy(copy);
   2944         jniThrowRuntimeException(env, "Unable to copy EVP_MD_CTX");
   2945         freeOpenSslErrorState();
   2946         return 0;
   2947     }
   2948 
   2949     JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p) => %p", ctx, copy);
   2950     return reinterpret_cast<uintptr_t>(copy);
   2951 }
   2952 
   2953 /*
   2954  * public static native int EVP_DigestFinal(int, byte[], int)
   2955  */
   2956 static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, jlong ctxRef,
   2957                                          jbyteArray hash, jint offset) {
   2958     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   2959     JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset);
   2960 
   2961     if (ctx == NULL || hash == NULL) {
   2962         jniThrowNullPointerException(env, "ctx == null || hash == null");
   2963         return -1;
   2964     }
   2965 
   2966     ScopedByteArrayRW hashBytes(env, hash);
   2967     if (hashBytes.get() == NULL) {
   2968         return -1;
   2969     }
   2970     unsigned int bytesWritten = -1;
   2971     int ok = EVP_DigestFinal(ctx,
   2972                              reinterpret_cast<unsigned char*>(hashBytes.get() + offset),
   2973                              &bytesWritten);
   2974     if (ok == 0) {
   2975         throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestFinal");
   2976     }
   2977     EVP_MD_CTX_destroy(ctx);
   2978 
   2979     JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d) => %d", ctx, hash, offset, bytesWritten);
   2980     return bytesWritten;
   2981 }
   2982 
   2983 /*
   2984  * public static native int EVP_DigestInit(int)
   2985  */
   2986 static jlong NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, jlong evpMdRef) {
   2987     EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
   2988     JNI_TRACE("NativeCrypto_EVP_DigestInit(%p)", evp_md);
   2989 
   2990     if (evp_md == NULL) {
   2991         jniThrowNullPointerException(env, NULL);
   2992         return 0;
   2993     }
   2994 
   2995     Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
   2996     if (ctx.get() == NULL) {
   2997         jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
   2998         return 0;
   2999     }
   3000     JNI_TRACE("NativeCrypto_EVP_DigestInit ctx=%p", ctx.get());
   3001 
   3002     int ok = EVP_DigestInit(ctx.get(), evp_md);
   3003     if (ok == 0) {
   3004         bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestInit");
   3005         if (exception) {
   3006             return 0;
   3007         }
   3008     }
   3009     return reinterpret_cast<uintptr_t>(ctx.release());
   3010 }
   3011 
   3012 /*
   3013  * public static native int EVP_get_digestbyname(java.lang.String)
   3014  */
   3015 static jlong NativeCrypto_EVP_get_digestbyname(JNIEnv* env, jclass, jstring algorithm) {
   3016     JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%p)", algorithm);
   3017 
   3018     if (algorithm == NULL) {
   3019         jniThrowNullPointerException(env, NULL);
   3020         return -1;
   3021     }
   3022 
   3023     ScopedUtfChars algorithmChars(env, algorithm);
   3024     if (algorithmChars.c_str() == NULL) {
   3025         return 0;
   3026     }
   3027     JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s)", algorithmChars.c_str());
   3028 
   3029     const EVP_MD* evp_md = EVP_get_digestbyname(algorithmChars.c_str());
   3030     if (evp_md == NULL) {
   3031         jniThrowRuntimeException(env, "Hash algorithm not found");
   3032         return 0;
   3033     }
   3034 
   3035     JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => %p", algorithmChars.c_str(), evp_md);
   3036     return reinterpret_cast<uintptr_t>(evp_md);
   3037 }
   3038 
   3039 /*
   3040  * public static native int EVP_MD_size(int)
   3041  */
   3042 static jint NativeCrypto_EVP_MD_size(JNIEnv* env, jclass, jint evpMdRef) {
   3043     EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
   3044     JNI_TRACE("NativeCrypto_EVP_MD_size(%p)", evp_md);
   3045 
   3046     if (evp_md == NULL) {
   3047         jniThrowNullPointerException(env, NULL);
   3048         return -1;
   3049     }
   3050 
   3051     int result = EVP_MD_size(evp_md);
   3052     JNI_TRACE("NativeCrypto_EVP_MD_size(%p) => %d", evp_md, result);
   3053     return result;
   3054 }
   3055 
   3056 /*
   3057  * public static int void EVP_MD_block_size(int)
   3058  */
   3059 static jint NativeCrypto_EVP_MD_block_size(JNIEnv* env, jclass, jlong evpMdRef) {
   3060     EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
   3061     JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p)", evp_md);
   3062 
   3063     if (evp_md == NULL) {
   3064         jniThrowNullPointerException(env, NULL);
   3065         return -1;
   3066     }
   3067 
   3068     int result = EVP_MD_block_size(evp_md);
   3069     JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p) => %d", evp_md, result);
   3070     return result;
   3071 }
   3072 
   3073 /*
   3074  * public static native void EVP_DigestUpdate(int, byte[], int, int)
   3075  */
   3076 static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, jlong ctxRef,
   3077                                           jbyteArray buffer, jint offset, jint length) {
   3078     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   3079     JNI_TRACE("NativeCrypto_EVP_DigestUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
   3080 
   3081     if (offset < 0 || length < 0) {
   3082         jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
   3083         return;
   3084     }
   3085 
   3086     if (ctx == NULL || buffer == NULL) {
   3087         jniThrowNullPointerException(env, NULL);
   3088         return;
   3089     }
   3090 
   3091     ScopedByteArrayRO bufferBytes(env, buffer);
   3092     if (bufferBytes.get() == NULL) {
   3093         return;
   3094     }
   3095     int ok = EVP_DigestUpdate(ctx,
   3096                               reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
   3097                               length);
   3098     if (ok == 0) {
   3099         throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestUpdate");
   3100     }
   3101 }
   3102 
   3103 static void NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jlong evpMdCtxRef,
   3104         const jlong evpMdRef, jlong pkeyRef) {
   3105     EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
   3106     const EVP_MD* md = reinterpret_cast<const EVP_MD*>(evpMdRef);
   3107     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   3108     JNI_TRACE("EVP_DigestSignInit(%p, %p, %p)", mdCtx, md, pkey);
   3109 
   3110     if (mdCtx == NULL) {
   3111          jniThrowNullPointerException(env, "mdCtx == null");
   3112          return;
   3113     }
   3114 
   3115     if (md == NULL) {
   3116          jniThrowNullPointerException(env, "md == null");
   3117          return;
   3118     }
   3119 
   3120     if (pkey == NULL) {
   3121          jniThrowNullPointerException(env, "pkey == null");
   3122          return;
   3123     }
   3124 
   3125     if (EVP_DigestSignInit(mdCtx, (EVP_PKEY_CTX **) NULL, md, (ENGINE *) NULL, pkey) <= 0) {
   3126         JNI_TRACE("ctx=%p EVP_DigestSignInit => threw exception", mdCtx);
   3127         throwExceptionIfNecessary(env, "EVP_DigestSignInit");
   3128         return;
   3129     }
   3130 
   3131     JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) => success", mdCtx, md, pkey);
   3132 }
   3133 
   3134 static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jint evpMdCtxRef,
   3135         jbyteArray inJavaBytes, jint inOffset, jint inLength)
   3136 {
   3137     EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
   3138     JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d)", mdCtx, inJavaBytes, inOffset, inLength);
   3139 
   3140     if (mdCtx == NULL) {
   3141          jniThrowNullPointerException(env, "mdCtx == null");
   3142          return;
   3143     }
   3144 
   3145     ScopedByteArrayRO inBytes(env, inJavaBytes);
   3146     if (inBytes.get() == NULL) {
   3147         return;
   3148     }
   3149 
   3150     if (inOffset < 0 || size_t(inOffset) > inBytes.size()) {
   3151         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inOffset");
   3152         return;
   3153     }
   3154 
   3155     const ssize_t inEnd = inOffset + inLength;
   3156     if (inEnd < 0 || size_t(inEnd) >= inBytes.size()) {
   3157         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "inLength");
   3158         return;
   3159     }
   3160 
   3161     const unsigned char *tmp = reinterpret_cast<const unsigned char *>(inBytes.get());
   3162     if (!EVP_DigestSignUpdate(mdCtx, tmp + inOffset, inLength)) {
   3163         JNI_TRACE("ctx=%p EVP_DigestSignUpdate => threw exception", mdCtx);
   3164         throwExceptionIfNecessary(env, "EVP_DigestSignUpdate");
   3165     }
   3166 
   3167     JNI_TRACE("EVP_DigestSignUpdate(%p, %p, %d, %d) => success", mdCtx, inJavaBytes, inOffset,
   3168             inLength);
   3169 }
   3170 
   3171 static jbyteArray NativeCrypto_EVP_DigestSignFinal(JNIEnv* env, jclass, jlong evpMdCtxRef)
   3172 {
   3173     EVP_MD_CTX* mdCtx = reinterpret_cast<EVP_MD_CTX*>(evpMdCtxRef);
   3174     JNI_TRACE("EVP_DigestSignFinal(%p)", mdCtx);
   3175 
   3176     if (mdCtx == NULL) {
   3177          jniThrowNullPointerException(env, "mdCtx == null");
   3178          return NULL;
   3179     }
   3180 
   3181     const size_t expectedSize = EVP_MD_CTX_size(mdCtx);
   3182     ScopedLocalRef<jbyteArray> outJavaBytes(env, env->NewByteArray(expectedSize));
   3183     if (outJavaBytes.get() == NULL) {
   3184         return NULL;
   3185     }
   3186     ScopedByteArrayRW outBytes(env, outJavaBytes.get());
   3187     if (outBytes.get() == NULL) {
   3188         return NULL;
   3189     }
   3190     unsigned char *tmp = reinterpret_cast<unsigned char*>(outBytes.get());
   3191     size_t len;
   3192     if (!EVP_DigestSignFinal(mdCtx, tmp, &len)) {
   3193         JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx);
   3194         throwExceptionIfNecessary(env, "EVP_DigestSignFinal");
   3195         return 0;
   3196     }
   3197 
   3198     if (len != expectedSize) {
   3199         jniThrowRuntimeException(env, "hash size unexpected");
   3200         return 0;
   3201     }
   3202 
   3203     JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, outJavaBytes.get());
   3204     return outJavaBytes.release();
   3205 }
   3206 
   3207 static jlong NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jstring algorithm) {
   3208     JNI_TRACE("NativeCrypto_EVP_SignInit(%p)", algorithm);
   3209 
   3210     if (algorithm == NULL) {
   3211         jniThrowNullPointerException(env, NULL);
   3212         return 0;
   3213     }
   3214 
   3215     Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
   3216     if (ctx.get() == NULL) {
   3217         jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
   3218         return 0;
   3219     }
   3220     JNI_TRACE("NativeCrypto_EVP_SignInit ctx=%p", ctx.get());
   3221 
   3222     ScopedUtfChars algorithmChars(env, algorithm);
   3223     if (algorithmChars.c_str() == NULL) {
   3224         return 0;
   3225     }
   3226     JNI_TRACE("NativeCrypto_EVP_SignInit algorithmChars=%s", algorithmChars.c_str());
   3227 
   3228     const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
   3229     if (digest == NULL) {
   3230         JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => hash not found", algorithmChars.c_str());
   3231         throwExceptionIfNecessary(env, "Hash algorithm not found");
   3232         return 0;
   3233     }
   3234 
   3235     int ok = EVP_SignInit(ctx.get(), digest);
   3236     if (ok == 0) {
   3237         bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignInit");
   3238         if (exception) {
   3239             JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => threw exception", algorithmChars.c_str());
   3240             return 0;
   3241         }
   3242     }
   3243 
   3244     JNI_TRACE("NativeCrypto_EVP_SignInit(%s) => %p", algorithmChars.c_str(), ctx.get());
   3245     return reinterpret_cast<uintptr_t>(ctx.release());
   3246 }
   3247 
   3248 /*
   3249  * public static native void EVP_SignUpdate(int, byte[], int, int)
   3250  */
   3251 static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jlong ctxRef,
   3252                                           jbyteArray buffer, jint offset, jint length) {
   3253     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   3254     JNI_TRACE("NativeCrypto_EVP_SignUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
   3255 
   3256     if (ctx == NULL || buffer == NULL) {
   3257         jniThrowNullPointerException(env, NULL);
   3258         return;
   3259     }
   3260 
   3261     ScopedByteArrayRO bufferBytes(env, buffer);
   3262     if (bufferBytes.get() == NULL) {
   3263         return;
   3264     }
   3265     int ok = EVP_SignUpdate(ctx,
   3266                             reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
   3267                             length);
   3268     if (ok == 0) {
   3269         throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignUpdate");
   3270     }
   3271 }
   3272 
   3273 /*
   3274  * public static native int EVP_SignFinal(int, byte[], int, int)
   3275  */
   3276 static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray signature,
   3277         jint offset, jlong pkeyRef) {
   3278     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   3279     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   3280     JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctx, signature, offset, pkey);
   3281 
   3282     if (ctx == NULL || pkey == NULL) {
   3283         jniThrowNullPointerException(env, NULL);
   3284         return -1;
   3285     }
   3286 
   3287     ScopedByteArrayRW signatureBytes(env, signature);
   3288     if (signatureBytes.get() == NULL) {
   3289         return -1;
   3290     }
   3291     unsigned int bytesWritten = -1;
   3292     int ok = EVP_SignFinal(ctx,
   3293                            reinterpret_cast<unsigned char*>(signatureBytes.get() + offset),
   3294                            &bytesWritten,
   3295                            pkey);
   3296     if (ok == 0) {
   3297         throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal");
   3298     }
   3299     JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u",
   3300               ctx, signature, offset, pkey, bytesWritten);
   3301 
   3302     return bytesWritten;
   3303 }
   3304 
   3305 /*
   3306  * public static native int EVP_VerifyInit(java.lang.String)
   3307  */
   3308 static jlong NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jstring algorithm) {
   3309     JNI_TRACE("NativeCrypto_EVP_VerifyInit(%p)", algorithm);
   3310 
   3311     if (algorithm == NULL) {
   3312         jniThrowNullPointerException(env, NULL);
   3313         return 0;
   3314     }
   3315 
   3316     Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
   3317     if (ctx.get() == NULL) {
   3318         jniThrowOutOfMemory(env, "Unable to allocate EVP_MD_CTX");
   3319         return 0;
   3320     }
   3321     JNI_TRACE("NativeCrypto_EVP_VerifyInit ctx=%p", ctx.get());
   3322 
   3323     ScopedUtfChars algorithmChars(env, algorithm);
   3324     if (algorithmChars.c_str() == NULL) {
   3325         return 0;
   3326     }
   3327     JNI_TRACE("NativeCrypto_EVP_VerifyInit algorithmChars=%s", algorithmChars.c_str());
   3328 
   3329     const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
   3330     if (digest == NULL) {
   3331         jniThrowRuntimeException(env, "Hash algorithm not found");
   3332         return 0;
   3333     }
   3334 
   3335     int ok = EVP_VerifyInit(ctx.get(), digest);
   3336     if (ok == 0) {
   3337         bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyInit");
   3338         if (exception) {
   3339             return 0;
   3340         }
   3341     }
   3342     return reinterpret_cast<uintptr_t>(ctx.release());
   3343 }
   3344 
   3345 /*
   3346  * public static native void EVP_VerifyUpdate(int, byte[], int, int)
   3347  */
   3348 static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jlong ctxRef,
   3349                                           jbyteArray buffer, jint offset, jint length) {
   3350     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   3351     JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
   3352 
   3353     if (ctx == NULL || buffer == NULL) {
   3354         jniThrowNullPointerException(env, NULL);
   3355         return;
   3356     }
   3357 
   3358     ScopedByteArrayRO bufferBytes(env, buffer);
   3359     if (bufferBytes.get() == NULL) {
   3360         return;
   3361     }
   3362     int ok = EVP_VerifyUpdate(ctx,
   3363                               reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
   3364                               length);
   3365     if (ok == 0) {
   3366         throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate");
   3367     }
   3368 }
   3369 
   3370 /*
   3371  * public static native int EVP_VerifyFinal(int, byte[], int, int, int)
   3372  */
   3373 static jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jlong ctxRef, jbyteArray buffer,
   3374                                         jint offset, jint length, jlong pkeyRef) {
   3375     EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
   3376     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   3377     JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)",
   3378               ctx, buffer, offset, length, pkey);
   3379 
   3380     if (ctx == NULL || buffer == NULL || pkey == NULL) {
   3381         jniThrowNullPointerException(env, NULL);
   3382         return -1;
   3383     }
   3384 
   3385     ScopedByteArrayRO bufferBytes(env, buffer);
   3386     if (bufferBytes.get() == NULL) {
   3387         return -1;
   3388     }
   3389     int ok = EVP_VerifyFinal(ctx,
   3390                              reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
   3391                              length,
   3392                              pkey);
   3393     if (ok < 0) {
   3394         throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal");
   3395     }
   3396 
   3397     /*
   3398      * For DSA keys, OpenSSL appears to have a bug where it returns
   3399      * errors for any result != 1. See dsa_ossl.c in dsa_do_verify
   3400      */
   3401     freeOpenSslErrorState();
   3402 
   3403     JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
   3404               ctx, buffer, offset, length, pkey, ok);
   3405 
   3406     return ok;
   3407 }
   3408 
   3409 static jlong NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) {
   3410     JNI_TRACE("EVP_get_cipherbyname(%p)", algorithm);
   3411     if (algorithm == NULL) {
   3412         JNI_TRACE("EVP_get_cipherbyname(%p) => threw exception algorithm == null", algorithm);
   3413         jniThrowNullPointerException(env, NULL);
   3414         return -1;
   3415     }
   3416 
   3417     ScopedUtfChars algorithmChars(env, algorithm);
   3418     if (algorithmChars.c_str() == NULL) {
   3419         return 0;
   3420     }
   3421     JNI_TRACE("EVP_get_cipherbyname(%p) => algorithm = %s", algorithm, algorithmChars.c_str());
   3422 
   3423     const EVP_CIPHER* evp_cipher = EVP_get_cipherbyname(algorithmChars.c_str());
   3424     if (evp_cipher == NULL) {
   3425         freeOpenSslErrorState();
   3426     }
   3427 
   3428     JNI_TRACE("EVP_get_cipherbyname(%s) => %p", algorithmChars.c_str(), evp_cipher);
   3429     return reinterpret_cast<uintptr_t>(evp_cipher);
   3430 }
   3431 
   3432 static void NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jlong ctxRef, jlong evpCipherRef,
   3433         jbyteArray keyArray, jbyteArray ivArray, jboolean encrypting) {
   3434     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3435     const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef);
   3436     JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d)", ctx, evpCipher, keyArray, ivArray,
   3437             encrypting ? 1 : 0);
   3438 
   3439     if (ctx == NULL) {
   3440         jniThrowNullPointerException(env, "ctx == null");
   3441         JNI_TRACE("EVP_CipherUpdate => ctx == null");
   3442         return;
   3443     }
   3444 
   3445     // The key can be null if we need to set extra parameters.
   3446     UniquePtr<unsigned char[]> keyPtr;
   3447     if (keyArray != NULL) {
   3448         ScopedByteArrayRO keyBytes(env, keyArray);
   3449         if (keyBytes.get() == NULL) {
   3450             return;
   3451         }
   3452 
   3453         keyPtr.reset(new unsigned char[keyBytes.size()]);
   3454         memcpy(keyPtr.get(), keyBytes.get(), keyBytes.size());
   3455     }
   3456 
   3457     // The IV can be null if we're using ECB.
   3458     UniquePtr<unsigned char[]> ivPtr;
   3459     if (ivArray != NULL) {
   3460         ScopedByteArrayRO ivBytes(env, ivArray);
   3461         if (ivBytes.get() == NULL) {
   3462             return;
   3463         }
   3464 
   3465         ivPtr.reset(new unsigned char[ivBytes.size()]);
   3466         memcpy(ivPtr.get(), ivBytes.get(), ivBytes.size());
   3467     }
   3468 
   3469     if (!EVP_CipherInit_ex(ctx, evpCipher, NULL, keyPtr.get(), ivPtr.get(), encrypting ? 1 : 0)) {
   3470         throwExceptionIfNecessary(env, "EVP_CipherInit_ex");
   3471         JNI_TRACE("EVP_CipherInit_ex => error initializing cipher");
   3472         return;
   3473     }
   3474 
   3475     JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d) => success", ctx, evpCipher, keyArray, ivArray,
   3476             encrypting ? 1 : 0);
   3477 }
   3478 
   3479 /*
   3480  *  public static native int EVP_CipherUpdate(int ctx, byte[] out, int outOffset, byte[] in,
   3481  *          int inOffset);
   3482  */
   3483 static jint NativeCrypto_EVP_CipherUpdate(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray,
   3484         jint outOffset, jbyteArray inArray, jint inOffset, jint inLength) {
   3485     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3486     JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d)", ctx, outArray, outOffset, inArray, inOffset);
   3487 
   3488     if (ctx == NULL) {
   3489         jniThrowNullPointerException(env, "ctx == null");
   3490         JNI_TRACE("ctx=%p EVP_CipherUpdate => ctx == null", ctx);
   3491         return 0;
   3492     }
   3493 
   3494     ScopedByteArrayRO inBytes(env, inArray);
   3495     if (inBytes.get() == NULL) {
   3496         return 0;
   3497     }
   3498     const size_t inSize = inBytes.size();
   3499     if (size_t(inOffset + inLength) > inSize) {
   3500         jniThrowException(env, "java/lang/IndexOutOfBoundsException",
   3501                 "in.length < (inSize + inOffset)");
   3502         return 0;
   3503     }
   3504 
   3505     ScopedByteArrayRW outBytes(env, outArray);
   3506     if (outBytes.get() == NULL) {
   3507         return 0;
   3508     }
   3509     const size_t outSize = outBytes.size();
   3510     if (size_t(outOffset + inLength) > outSize) {
   3511         jniThrowException(env, "java/lang/IndexOutOfBoundsException",
   3512                 "out.length < inSize + outOffset + blockSize - 1");
   3513         return 0;
   3514     }
   3515 
   3516     JNI_TRACE("ctx=%p EVP_CipherUpdate in=%p in.length=%d inOffset=%d inLength=%d out=%p out.length=%d outOffset=%d",
   3517             ctx, inBytes.get(), inBytes.size(), inOffset, inLength, outBytes.get(), outBytes.size(), outOffset);
   3518 
   3519     unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
   3520     const unsigned char* in = reinterpret_cast<const unsigned char*>(inBytes.get());
   3521 
   3522     int outl;
   3523     if (!EVP_CipherUpdate(ctx, out + outOffset, &outl, in + inOffset, inLength)) {
   3524         throwExceptionIfNecessary(env, "EVP_CipherUpdate");
   3525         JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx);
   3526         return 0;
   3527     }
   3528 
   3529     JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d) => %d", ctx, outArray, outOffset, inArray,
   3530             inOffset, outl);
   3531     return outl;
   3532 }
   3533 
   3534 static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jlong ctxRef, jbyteArray outArray,
   3535         jint outOffset) {
   3536     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3537     JNI_TRACE("EVP_CipherFinal_ex(%p, %p, %d)", ctx, outArray, outOffset);
   3538 
   3539     if (ctx == NULL) {
   3540         jniThrowNullPointerException(env, "ctx == null");
   3541         JNI_TRACE("ctx=%p EVP_CipherFinal_ex => ctx == null", ctx);
   3542         return 0;
   3543     }
   3544 
   3545     ScopedByteArrayRW outBytes(env, outArray);
   3546     if (outBytes.get() == NULL) {
   3547         return 0;
   3548     }
   3549 
   3550     unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
   3551 
   3552     int outl;
   3553     if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) {
   3554         throwExceptionIfNecessary(env, "EVP_CipherFinal_ex");
   3555         JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw error", ctx);
   3556         return 0;
   3557     }
   3558 
   3559     JNI_TRACE("EVP_CipherFinal(%p, %p, %d) => %d", ctx, outArray, outOffset, outl);
   3560     return outl;
   3561 }
   3562 
   3563 static jint NativeCrypto_EVP_CIPHER_iv_length(JNIEnv* env, jclass, jlong evpCipherRef) {
   3564     const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef);
   3565     JNI_TRACE("EVP_CIPHER_iv_length(%p)", evpCipher);
   3566 
   3567     if (evpCipher == NULL) {
   3568         jniThrowNullPointerException(env, "evpCipher == null");
   3569         JNI_TRACE("EVP_CIPHER_iv_length => evpCipher == null");
   3570         return 0;
   3571     }
   3572 
   3573     const int ivLength = EVP_CIPHER_iv_length(evpCipher);
   3574     JNI_TRACE("EVP_CIPHER_iv_length(%p) => %d", evpCipher, ivLength);
   3575     return ivLength;
   3576 }
   3577 
   3578 static jlong NativeCrypto_EVP_CIPHER_CTX_new(JNIEnv* env, jclass) {
   3579     JNI_TRACE("EVP_CIPHER_CTX_new()");
   3580 
   3581     Unique_EVP_CIPHER_CTX ctx(EVP_CIPHER_CTX_new());
   3582     if (ctx.get() == NULL) {
   3583         jniThrowOutOfMemory(env, "Unable to allocate cipher context");
   3584         JNI_TRACE("EVP_CipherInit_ex => context allocation error");
   3585         return 0;
   3586     }
   3587 
   3588     JNI_TRACE("EVP_CIPHER_CTX_new() => %p", ctx.get());
   3589     return reinterpret_cast<uintptr_t>(ctx.release());
   3590 }
   3591 
   3592 static jint NativeCrypto_EVP_CIPHER_CTX_block_size(JNIEnv* env, jclass, jlong ctxRef) {
   3593     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3594     JNI_TRACE("EVP_CIPHER_CTX_block_size(%p)", ctx);
   3595 
   3596     if (ctx == NULL) {
   3597         jniThrowNullPointerException(env, "ctx == null");
   3598         JNI_TRACE("ctx=%p EVP_CIPHER_CTX_block_size => ctx == null", ctx);
   3599         return 0;
   3600     }
   3601 
   3602     int blockSize = EVP_CIPHER_CTX_block_size(ctx);
   3603     JNI_TRACE("EVP_CIPHER_CTX_block_size(%p) => %d", ctx, blockSize);
   3604     return blockSize;
   3605 }
   3606 
   3607 static jint NativeCrypto_get_EVP_CIPHER_CTX_buf_len(JNIEnv* env, jclass, jlong ctxRef) {
   3608     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3609     JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p)", ctx);
   3610 
   3611     if (ctx == NULL) {
   3612         jniThrowNullPointerException(env, "ctx == null");
   3613         JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_buf_len => ctx == null", ctx);
   3614         return 0;
   3615     }
   3616 
   3617     int buf_len = ctx->buf_len;
   3618     JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p) => %d", ctx, buf_len);
   3619     return buf_len;
   3620 }
   3621 
   3622 static void NativeCrypto_EVP_CIPHER_CTX_set_padding(JNIEnv* env, jclass, jlong ctxRef, jboolean enablePaddingBool) {
   3623     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3624     jint enablePadding = enablePaddingBool ? 1 : 0;
   3625     JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d)", ctx, enablePadding);
   3626 
   3627     if (ctx == NULL) {
   3628         jniThrowNullPointerException(env, "ctx == null");
   3629         JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_padding => ctx == null", ctx);
   3630         return;
   3631     }
   3632 
   3633     EVP_CIPHER_CTX_set_padding(ctx, enablePadding); // Not void, but always returns 1.
   3634     JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d) => success", ctx, enablePadding);
   3635 }
   3636 
   3637 static void NativeCrypto_EVP_CIPHER_CTX_set_key_length(JNIEnv* env, jclass, jlong ctxRef,
   3638         jint keySizeBits) {
   3639     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3640     JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d)", ctx, keySizeBits);
   3641 
   3642     if (ctx == NULL) {
   3643         jniThrowNullPointerException(env, "ctx == null");
   3644         JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_key_length => ctx == null", ctx);
   3645         return;
   3646     }
   3647 
   3648     if (!EVP_CIPHER_CTX_set_key_length(ctx, keySizeBits)) {
   3649         throwExceptionIfNecessary(env, "NativeCrypto_EVP_CIPHER_CTX_set_key_length");
   3650         JNI_TRACE("NativeCrypto_EVP_CIPHER_CTX_set_key_length => threw error");
   3651         return;
   3652     }
   3653     JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d) => success", ctx, keySizeBits);
   3654 }
   3655 
   3656 static void NativeCrypto_EVP_CIPHER_CTX_cleanup(JNIEnv* env, jclass, jlong ctxRef) {
   3657     EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
   3658     JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p)", ctx);
   3659 
   3660     if (ctx != NULL) {
   3661         if (!EVP_CIPHER_CTX_cleanup(ctx)) {
   3662             throwExceptionIfNecessary(env, "EVP_CIPHER_CTX_cleanup");
   3663             JNI_TRACE("EVP_CIPHER_CTX_cleanup => threw error");
   3664             return;
   3665         }
   3666     }
   3667     JNI_TRACE("EVP_CIPHER_CTX_cleanup(%p) => success", ctx);
   3668 }
   3669 
   3670 /**
   3671  * public static native void RAND_seed(byte[]);
   3672  */
   3673 static void NativeCrypto_RAND_seed(JNIEnv* env, jclass, jbyteArray seed) {
   3674     JNI_TRACE("NativeCrypto_RAND_seed seed=%p", seed);
   3675     ScopedByteArrayRO randseed(env, seed);
   3676     if (randseed.get() == NULL) {
   3677         return;
   3678     }
   3679     RAND_seed(randseed.get(), randseed.size());
   3680 }
   3681 
   3682 static jint NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) {
   3683     JNI_TRACE("NativeCrypto_RAND_load_file filename=%p max_bytes=%lld", filename, max_bytes);
   3684     ScopedUtfChars file(env, filename);
   3685     if (file.c_str() == NULL) {
   3686         return -1;
   3687     }
   3688     int result = RAND_load_file(file.c_str(), max_bytes);
   3689     JNI_TRACE("NativeCrypto_RAND_load_file file=%s => %d", file.c_str(), result);
   3690     return result;
   3691 }
   3692 
   3693 static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) {
   3694     JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output);
   3695 
   3696     ScopedByteArrayRW outputBytes(env, output);
   3697     if (outputBytes.get() == NULL) {
   3698         return;
   3699     }
   3700 
   3701     unsigned char* tmp = reinterpret_cast<unsigned char*>(outputBytes.get());
   3702     if (RAND_bytes(tmp, outputBytes.size()) <= 0) {
   3703         throwExceptionIfNecessary(env, "NativeCrypto_RAND_bytes");
   3704         JNI_TRACE("tmp=%p NativeCrypto_RAND_bytes => threw error", tmp);
   3705         return;
   3706     }
   3707 
   3708     JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output);
   3709 }
   3710 
   3711 static jint NativeCrypto_OBJ_txt2nid(JNIEnv* env, jclass, jstring oidStr) {
   3712     JNI_TRACE("OBJ_txt2nid(%p)", oidStr);
   3713 
   3714     ScopedUtfChars oid(env, oidStr);
   3715     if (oid.c_str() == NULL) {
   3716         return 0;
   3717     }
   3718 
   3719     int nid = OBJ_txt2nid(oid.c_str());
   3720     JNI_TRACE("OBJ_txt2nid(%s) => %d", oid.c_str(), nid);
   3721     return nid;
   3722 }
   3723 
   3724 static jstring NativeCrypto_OBJ_txt2nid_longName(JNIEnv* env, jclass, jstring oidStr) {
   3725     JNI_TRACE("OBJ_txt2nid_longName(%p)", oidStr);
   3726 
   3727     ScopedUtfChars oid(env, oidStr);
   3728     if (oid.c_str() == NULL) {
   3729         return NULL;
   3730     }
   3731 
   3732     JNI_TRACE("OBJ_txt2nid_longName(%s)", oid.c_str());
   3733 
   3734     int nid = OBJ_txt2nid(oid.c_str());
   3735     if (nid == NID_undef) {
   3736         JNI_TRACE("OBJ_txt2nid_longName(%s) => NID_undef", oid.c_str());
   3737         freeOpenSslErrorState();
   3738         return NULL;
   3739     }
   3740 
   3741     const char* longName = OBJ_nid2ln(nid);
   3742     JNI_TRACE("OBJ_txt2nid_longName(%s) => %s", oid.c_str(), longName);
   3743     return env->NewStringUTF(longName);
   3744 }
   3745 
   3746 static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, ASN1_OBJECT* obj) {
   3747     /*
   3748      * The OBJ_obj2txt API doesn't "measure" if you pass in NULL as the buffer.
   3749      * Just make a buffer that's large enough here. The documentation recommends
   3750      * 80 characters.
   3751      */
   3752     char output[128];
   3753     int ret = OBJ_obj2txt(output, sizeof(output), obj, 1);
   3754     if (ret < 0) {
   3755         throwExceptionIfNecessary(env, "ASN1_OBJECT_to_OID_string");
   3756         return NULL;
   3757     } else if (size_t(ret) >= sizeof(output)) {
   3758         jniThrowRuntimeException(env, "ASN1_OBJECT_to_OID_string buffer too small");
   3759         return NULL;
   3760     }
   3761 
   3762     JNI_TRACE("ASN1_OBJECT_to_OID_string(%p) => %s", obj, output);
   3763     return env->NewStringUTF(output);
   3764 }
   3765 
   3766 static jlong NativeCrypto_create_BIO_InputStream(JNIEnv* env, jclass, jobject streamObj) {
   3767     JNI_TRACE("create_BIO_InputStream(%p)", streamObj);
   3768 
   3769     if (streamObj == NULL) {
   3770         jniThrowNullPointerException(env, "stream == null");
   3771         return 0;
   3772     }
   3773 
   3774     Unique_BIO bio(BIO_new(&stream_bio_method));
   3775     if (bio.get() == NULL) {
   3776         return 0;
   3777     }
   3778 
   3779     bio_stream_assign(bio.get(), new BIO_InputStream(streamObj));
   3780 
   3781     JNI_TRACE("create_BIO_InputStream(%p) => %p", streamObj, bio.get());
   3782     return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release()));
   3783 }
   3784 
   3785 static jlong NativeCrypto_create_BIO_OutputStream(JNIEnv* env, jclass, jobject streamObj) {
   3786     JNI_TRACE("create_BIO_OutputStream(%p)", streamObj);
   3787 
   3788     if (streamObj == NULL) {
   3789         jniThrowNullPointerException(env, "stream == null");
   3790         return 0;
   3791     }
   3792 
   3793     Unique_BIO bio(BIO_new(&stream_bio_method));
   3794     if (bio.get() == NULL) {
   3795         return 0;
   3796     }
   3797 
   3798     bio_stream_assign(bio.get(), new BIO_OutputStream(streamObj));
   3799 
   3800     JNI_TRACE("create_BIO_OutputStream(%p) => %p", streamObj, bio.get());
   3801     return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release()));
   3802 }
   3803 
   3804 static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
   3805     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   3806     JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes);
   3807 
   3808     if (outputJavaBytes == NULL) {
   3809         jniThrowNullPointerException(env, "output == null");
   3810         JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes);
   3811         return 0;
   3812     }
   3813 
   3814     int outputSize = env->GetArrayLength(outputJavaBytes);
   3815 
   3816     UniquePtr<unsigned char[]> buffer(new unsigned char[outputSize]);
   3817     if (buffer.get() == NULL) {
   3818         jniThrowOutOfMemory(env, "Unable to allocate buffer for read");
   3819         return 0;
   3820     }
   3821 
   3822     int read = BIO_read(bio, buffer.get(), outputSize);
   3823     if (read <= 0) {
   3824         jniThrowException(env, "java/io/IOException", "BIO_read");
   3825         JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes);
   3826         return 0;
   3827     }
   3828 
   3829     env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get()));
   3830     JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read);
   3831     return read;
   3832 }
   3833 
   3834 static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes,
   3835         jint offset, jint length) {
   3836     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   3837     JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length);
   3838 
   3839     if (inputJavaBytes == NULL) {
   3840         jniThrowNullPointerException(env, "input == null");
   3841         return;
   3842     }
   3843 
   3844     if (offset < 0 || length < 0) {
   3845         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "offset < 0 || length < 0");
   3846         JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
   3847         return;
   3848     }
   3849 
   3850     int inputSize = env->GetArrayLength(inputJavaBytes);
   3851     if (inputSize < offset + length) {
   3852         jniThrowException(env, "java/lang/IndexOutOfBoundsException",
   3853                 "input.length < offset + length");
   3854         JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length);
   3855         return;
   3856     }
   3857 
   3858     UniquePtr<unsigned char[]> buffer(new unsigned char[length]);
   3859     if (buffer.get() == NULL) {
   3860         jniThrowOutOfMemory(env, "Unable to allocate buffer for write");
   3861         return;
   3862     }
   3863 
   3864     env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get()));
   3865     if (BIO_write(bio, buffer.get(), length) != length) {
   3866         freeOpenSslErrorState();
   3867         jniThrowException(env, "java/io/IOException", "BIO_write");
   3868         JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length);
   3869         return;
   3870     }
   3871 
   3872     JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length);
   3873 }
   3874 
   3875 static void NativeCrypto_BIO_free(JNIEnv* env, jclass, jlong bioRef) {
   3876     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   3877     JNI_TRACE("BIO_free(%p)", bio);
   3878 
   3879     if (bio == NULL) {
   3880         jniThrowNullPointerException(env, "bio == null");
   3881         return;
   3882     }
   3883 
   3884     BIO_free(bio);
   3885 }
   3886 
   3887 static jstring X509_NAME_to_jstring(JNIEnv* env, X509_NAME* name, unsigned long flags) {
   3888     JNI_TRACE("X509_NAME_to_jstring(%p)", name);
   3889 
   3890     Unique_BIO buffer(BIO_new(BIO_s_mem()));
   3891     if (buffer.get() == NULL) {
   3892         jniThrowOutOfMemory(env, "Unable to allocate BIO");
   3893         JNI_TRACE("X509_NAME_to_jstring(%p) => threw error", name);
   3894         return NULL;
   3895     }
   3896 
   3897     /* Don't interpret the string. */
   3898     flags &= ~(ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_MSB);
   3899 
   3900     /* Write in given format and null terminate. */
   3901     X509_NAME_print_ex(buffer.get(), name, 0, flags);
   3902     BIO_write(buffer.get(), "\0", 1);
   3903 
   3904     char *tmp;
   3905     BIO_get_mem_data(buffer.get(), &tmp);
   3906     JNI_TRACE("X509_NAME_to_jstring(%p) => \"%s\"", name, tmp);
   3907     return env->NewStringUTF(tmp);
   3908 }
   3909 
   3910 
   3911 /**
   3912  * Converts GENERAL_NAME items to the output format expected in
   3913  * X509Certificate#getSubjectAlternativeNames and
   3914  * X509Certificate#getIssuerAlternativeNames return.
   3915  */
   3916 static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) {
   3917     switch (gen->type) {
   3918     case GEN_EMAIL:
   3919     case GEN_DNS:
   3920     case GEN_URI: {
   3921         // This must not be a T61String and must not contain NULLs.
   3922         const char* data = reinterpret_cast<const char*>(ASN1_STRING_data(gen->d.ia5));
   3923         ssize_t len = ASN1_STRING_length(gen->d.ia5);
   3924         if ((len == static_cast<ssize_t>(strlen(data)))
   3925                 && (ASN1_PRINTABLE_type(ASN1_STRING_data(gen->d.ia5), len) != V_ASN1_T61STRING)) {
   3926             JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI \"%s\"", gen, data);
   3927             return env->NewStringUTF(data);
   3928         } else {
   3929             jniThrowException(env, "java/security/cert/CertificateParsingException",
   3930                     "Invalid dNSName encoding");
   3931             JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI invalid", gen);
   3932             return NULL;
   3933         }
   3934     }
   3935     case GEN_DIRNAME:
   3936         /* Write in RFC 2253 format */
   3937         return X509_NAME_to_jstring(env, gen->d.directoryName, XN_FLAG_RFC2253);
   3938     case GEN_IPADD: {
   3939         const void *ip = reinterpret_cast<const void *>(gen->d.ip->data);
   3940         if (gen->d.ip->length == 4) {
   3941             // IPv4
   3942             UniquePtr<char[]> buffer(new char[INET_ADDRSTRLEN]);
   3943             if (inet_ntop(AF_INET, ip, buffer.get(), INET_ADDRSTRLEN) != NULL) {
   3944                 JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 %s", gen, buffer.get());
   3945                 return env->NewStringUTF(buffer.get());
   3946             } else {
   3947                 JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 failed %s", gen, strerror(errno));
   3948             }
   3949         } else if (gen->d.ip->length == 16) {
   3950             // IPv6
   3951             UniquePtr<char[]> buffer(new char[INET6_ADDRSTRLEN]);
   3952             if (inet_ntop(AF_INET6, ip, buffer.get(), INET6_ADDRSTRLEN) != NULL) {
   3953                 JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 %s", gen, buffer.get());
   3954                 return env->NewStringUTF(buffer.get());
   3955             } else {
   3956                 JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 failed %s", gen, strerror(errno));
   3957             }
   3958         }
   3959 
   3960         /* Invalid IP encodings are pruned out without throwing an exception. */
   3961         return NULL;
   3962     }
   3963     case GEN_RID:
   3964         return ASN1_OBJECT_to_OID_string(env, gen->d.registeredID);
   3965     case GEN_OTHERNAME:
   3966     case GEN_X400:
   3967     default:
   3968         return ASN1ToByteArray<GENERAL_NAME, i2d_GENERAL_NAME>(env, gen);
   3969     }
   3970 
   3971     return NULL;
   3972 }
   3973 
   3974 #define GN_STACK_SUBJECT_ALT_NAME 1
   3975 #define GN_STACK_ISSUER_ALT_NAME 2
   3976 
   3977 static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass, jlong x509Ref,
   3978         jint type) {
   3979     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   3980     JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d)", x509, type);
   3981 
   3982     if (x509 == NULL) {
   3983         jniThrowNullPointerException(env, "x509 == null");
   3984         JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => x509 == null", x509, type);
   3985         return NULL;
   3986     }
   3987 
   3988     X509_check_ca(x509);
   3989 
   3990     STACK_OF(GENERAL_NAME)* gn_stack;
   3991     Unique_sk_GENERAL_NAME stackHolder;
   3992     if (type == GN_STACK_SUBJECT_ALT_NAME) {
   3993         gn_stack = x509->altname;
   3994     } else if (type == GN_STACK_ISSUER_ALT_NAME) {
   3995         stackHolder.reset(
   3996                 static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(x509, NID_issuer_alt_name,
   3997                         NULL, NULL)));
   3998         gn_stack = stackHolder.get();
   3999     } else {
   4000         JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => unknown type", x509, type);
   4001         return NULL;
   4002     }
   4003 
   4004     int count = sk_GENERAL_NAME_num(gn_stack);
   4005     if (count <= 0) {
   4006         JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no entries)", x509, type);
   4007         return NULL;
   4008     }
   4009 
   4010     /*
   4011      * Keep track of how many originally so we can ignore any invalid
   4012      * values later.
   4013      */
   4014     const int origCount = count;
   4015 
   4016     ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, objectArrayClass, NULL));
   4017     for (int i = 0, j = 0; i < origCount; i++, j++) {
   4018         GENERAL_NAME* gen = sk_GENERAL_NAME_value(gn_stack, i);
   4019         ScopedLocalRef<jobject> val(env, GENERAL_NAME_to_jobject(env, gen));
   4020         if (env->ExceptionCheck()) {
   4021             JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => threw exception parsing gen name",
   4022                     x509, type);
   4023             return NULL;
   4024         }
   4025 
   4026         /*
   4027          * If it's NULL, we'll have to skip this, reduce the number of total
   4028          * entries, and fix up the array later.
   4029          */
   4030         if (val.get() == NULL) {
   4031             j--;
   4032             count--;
   4033             continue;
   4034         }
   4035 
   4036         ScopedLocalRef<jobjectArray> item(env, env->NewObjectArray(2, objectClass, NULL));
   4037 
   4038         ScopedLocalRef<jobject> type(env, env->CallStaticObjectMethod(integerClass,
   4039                 integer_valueOfMethod, gen->type));
   4040         env->SetObjectArrayElement(item.get(), 0, type.get());
   4041         env->SetObjectArrayElement(item.get(), 1, val.get());
   4042 
   4043         env->SetObjectArrayElement(joa.get(), j, item.get());
   4044     }
   4045 
   4046     if (count == 0) {
   4047         JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to 0; returning NULL",
   4048                 x509, type, origCount);
   4049         joa.reset(NULL);
   4050     } else if (origCount != count) {
   4051         JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to %d", x509, type,
   4052                 origCount, count);
   4053 
   4054         ScopedLocalRef<jobjectArray> joa_copy(env, env->NewObjectArray(count, objectArrayClass,
   4055                 NULL));
   4056 
   4057         for (int i = 0; i < count; i++) {
   4058             ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(joa.get(), i));
   4059             env->SetObjectArrayElement(joa_copy.get(), i, item.get());
   4060         }
   4061 
   4062         joa.reset(joa_copy.release());
   4063     }
   4064 
   4065     JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => %d entries", x509, type, count);
   4066     return joa.release();
   4067 }
   4068 
   4069 static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref) {
   4070     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4071     JNI_TRACE("X509_get_notBefore(%p)", x509);
   4072 
   4073     if (x509 == NULL) {
   4074         jniThrowNullPointerException(env, "x509 == null");
   4075         JNI_TRACE("X509_get_notBefore(%p) => x509 == null", x509);
   4076         return 0;
   4077     }
   4078 
   4079     ASN1_TIME* notBefore = X509_get_notBefore(x509);
   4080     JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore);
   4081     return reinterpret_cast<uintptr_t>(notBefore);
   4082 }
   4083 
   4084 static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref) {
   4085     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4086     JNI_TRACE("X509_get_notAfter(%p)", x509);
   4087 
   4088     if (x509 == NULL) {
   4089         jniThrowNullPointerException(env, "x509 == null");
   4090         JNI_TRACE("X509_get_notAfter(%p) => x509 == null", x509);
   4091         return 0;
   4092     }
   4093 
   4094     ASN1_TIME* notAfter = X509_get_notAfter(x509);
   4095     JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter);
   4096     return reinterpret_cast<uintptr_t>(notAfter);
   4097 }
   4098 
   4099 static long NativeCrypto_X509_get_version(JNIEnv*, jclass, jlong x509Ref) {
   4100     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4101     JNI_TRACE("X509_get_version(%p)", x509);
   4102 
   4103     long version = X509_get_version(x509);
   4104     JNI_TRACE("X509_get_version(%p) => %ld", x509, version);
   4105     return version;
   4106 }
   4107 
   4108 template<typename T>
   4109 static jbyteArray get_X509Type_serialNumber(JNIEnv* env, T* x509Type, ASN1_INTEGER* (*get_serial_func)(T*)) {
   4110     JNI_TRACE("get_X509Type_serialNumber(%p)", x509Type);
   4111 
   4112     if (x509Type == NULL) {
   4113         jniThrowNullPointerException(env, "x509Type == null");
   4114         JNI_TRACE("get_X509Type_serialNumber(%p) => x509Type == null", x509Type);
   4115         return NULL;
   4116     }
   4117 
   4118     ASN1_INTEGER* serialNumber = get_serial_func(x509Type);
   4119     Unique_BIGNUM serialBn(ASN1_INTEGER_to_BN(serialNumber, NULL));
   4120     if (serialBn.get() == NULL) {
   4121         JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
   4122         return NULL;
   4123     }
   4124 
   4125     ScopedLocalRef<jbyteArray> serialArray(env, bignumToArray(env, serialBn.get(), "serialBn"));
   4126     if (env->ExceptionCheck()) {
   4127         JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
   4128         return NULL;
   4129     }
   4130 
   4131     JNI_TRACE("X509_get_serialNumber(%p) => %p", x509Type, serialArray.get());
   4132     return serialArray.release();
   4133 }
   4134 
   4135 /* OpenSSL includes set_serialNumber but not get. */
   4136 #if !defined(X509_REVOKED_get_serialNumber)
   4137 static ASN1_INTEGER* X509_REVOKED_get_serialNumber(X509_REVOKED* x) {
   4138     return x->serialNumber;
   4139 }
   4140 #endif
   4141 
   4142 static jbyteArray NativeCrypto_X509_get_serialNumber(JNIEnv* env, jclass, jlong x509Ref) {
   4143     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4144     JNI_TRACE("X509_get_serialNumber(%p)", x509);
   4145     return get_X509Type_serialNumber<X509>(env, x509, X509_get_serialNumber);
   4146 }
   4147 
   4148 static jbyteArray NativeCrypto_X509_REVOKED_get_serialNumber(JNIEnv* env, jclass, jlong x509RevokedRef) {
   4149     X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4150     JNI_TRACE("X509_REVOKED_get_serialNumber(%p)", revoked);
   4151     return get_X509Type_serialNumber<X509_REVOKED>(env, revoked, X509_REVOKED_get_serialNumber);
   4152 }
   4153 
   4154 static void NativeCrypto_X509_verify(JNIEnv* env, jclass, jlong x509Ref, jlong pkeyRef) {
   4155     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4156     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   4157     JNI_TRACE("X509_verify(%p, %p)", x509, pkey);
   4158 
   4159     if (x509 == NULL) {
   4160         jniThrowNullPointerException(env, "x509 == null");
   4161         JNI_TRACE("X509_verify(%p, %p) => x509 == null", x509, pkey);
   4162         return;
   4163     }
   4164 
   4165     if (pkey == NULL) {
   4166         jniThrowNullPointerException(env, "pkey == null");
   4167         JNI_TRACE("X509_verify(%p, %p) => pkey == null", x509, pkey);
   4168         return;
   4169     }
   4170 
   4171     if (X509_verify(x509, pkey) != 1) {
   4172         throwExceptionIfNecessary(env, "X509_verify");
   4173         JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey);
   4174     } else {
   4175         JNI_TRACE("X509_verify(%p, %p) => verify success", x509, pkey);
   4176     }
   4177 }
   4178 
   4179 static jbyteArray NativeCrypto_get_X509_cert_info_enc(JNIEnv* env, jclass, jlong x509Ref) {
   4180     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4181     JNI_TRACE("get_X509_cert_info_enc(%p)", x509);
   4182     return ASN1ToByteArray<X509_CINF, i2d_X509_CINF>(env, x509->cert_info);
   4183 }
   4184 
   4185 static jint NativeCrypto_get_X509_ex_flags(JNIEnv* env, jclass, jlong x509Ref) {
   4186     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4187     JNI_TRACE("get_X509_ex_flags(%p)", x509);
   4188 
   4189     if (x509 == NULL) {
   4190         jniThrowNullPointerException(env, "x509 == null");
   4191         JNI_TRACE("get_X509_ex_flags(%p) => x509 == null", x509);
   4192         return 0;
   4193     }
   4194 
   4195     X509_check_ca(x509);
   4196 
   4197     return x509->ex_flags;
   4198 }
   4199 
   4200 static jboolean NativeCrypto_X509_check_issued(JNIEnv*, jclass, jlong x509Ref1, jlong x509Ref2) {
   4201     X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1));
   4202     X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2));
   4203     JNI_TRACE("X509_check_issued(%p, %p)", x509_1, x509_2);
   4204 
   4205     int ret = X509_check_issued(x509_1, x509_2);
   4206     JNI_TRACE("X509_check_issued(%p, %p) => %d", x509_1, x509_2, ret);
   4207     return ret;
   4208 }
   4209 
   4210 static void get_X509_signature(X509 *x509, ASN1_BIT_STRING** signature) {
   4211     *signature = x509->signature;
   4212 }
   4213 
   4214 static void get_X509_CRL_signature(X509_CRL *crl, ASN1_BIT_STRING** signature) {
   4215     *signature = crl->signature;
   4216 }
   4217 
   4218 template<typename T>
   4219 static jbyteArray get_X509Type_signature(JNIEnv* env, T* x509Type, void (*get_signature_func)(T*, ASN1_BIT_STRING**)) {
   4220     JNI_TRACE("get_X509Type_signature(%p)", x509Type);
   4221 
   4222     if (x509Type == NULL) {
   4223         jniThrowNullPointerException(env, "x509Type == null");
   4224         JNI_TRACE("get_X509Type_signature(%p) => x509Type == null", x509Type);
   4225         return NULL;
   4226     }
   4227 
   4228     ASN1_BIT_STRING* signature;
   4229     get_signature_func(x509Type, &signature);
   4230 
   4231     ScopedLocalRef<jbyteArray> signatureArray(env, env->NewByteArray(signature->length));
   4232     if (env->ExceptionCheck()) {
   4233         JNI_TRACE("get_X509Type_signature(%p) => threw exception", x509Type);
   4234         return NULL;
   4235     }
   4236 
   4237     ScopedByteArrayRW signatureBytes(env, signatureArray.get());
   4238     if (signatureBytes.get() == NULL) {
   4239         JNI_TRACE("get_X509Type_signature(%p) => using byte array failed", x509Type);
   4240         return NULL;
   4241     }
   4242 
   4243     memcpy(signatureBytes.get(), signature->data, signature->length);
   4244 
   4245     JNI_TRACE("get_X509Type_signature(%p) => %p (%d bytes)", x509Type, signatureArray.get(),
   4246             signature->length);
   4247     return signatureArray.release();
   4248 }
   4249 
   4250 static jbyteArray NativeCrypto_get_X509_signature(JNIEnv* env, jclass, jlong x509Ref) {
   4251     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4252     JNI_TRACE("get_X509_signature(%p)", x509);
   4253     return get_X509Type_signature<X509>(env, x509, get_X509_signature);
   4254 }
   4255 
   4256 static jbyteArray NativeCrypto_get_X509_CRL_signature(JNIEnv* env, jclass, jlong x509CrlRef) {
   4257     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4258     JNI_TRACE("get_X509_CRL_signature(%p)", crl);
   4259     return get_X509Type_signature<X509_CRL>(env, crl, get_X509_CRL_signature);
   4260 }
   4261 
   4262 static jlong NativeCrypto_X509_CRL_get0_by_cert(JNIEnv* env, jclass, jlong x509crlRef, jlong x509Ref) {
   4263     X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
   4264     X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
   4265     JNI_TRACE("X509_CRL_get0_by_cert(%p, %p)", x509crl, x509);
   4266 
   4267     if (x509crl == NULL) {
   4268         jniThrowNullPointerException(env, "x509crl == null");
   4269         JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509crl == null", x509crl, x509);
   4270         return 0;
   4271     } else if (x509 == NULL) {
   4272         jniThrowNullPointerException(env, "x509 == null");
   4273         JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509 == null", x509crl, x509);
   4274         return 0;
   4275     }
   4276 
   4277     X509_REVOKED* revoked = NULL;
   4278     int ret = X509_CRL_get0_by_cert(x509crl, &revoked, x509);
   4279     if (ret == 0) {
   4280         JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => none", x509crl, x509);
   4281         return 0;
   4282     }
   4283 
   4284     JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, x509, revoked);
   4285     return reinterpret_cast<uintptr_t>(revoked);
   4286 }
   4287 
   4288 static jlong NativeCrypto_X509_CRL_get0_by_serial(JNIEnv* env, jclass, jlong x509crlRef, jbyteArray serialArray) {
   4289     X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
   4290     JNI_TRACE("X509_CRL_get0_by_serial(%p, %p)", x509crl, serialArray);
   4291 
   4292     if (x509crl == NULL) {
   4293         jniThrowNullPointerException(env, "x509crl == null");
   4294         JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => crl == null", x509crl, serialArray);
   4295         return 0;
   4296     }
   4297 
   4298     Unique_BIGNUM serialBn(BN_new());
   4299     if (serialBn.get() == NULL) {
   4300         JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN allocation failed", x509crl, serialArray);
   4301         return 0;
   4302     }
   4303 
   4304     BIGNUM* serialBare = serialBn.get();
   4305     if (!arrayToBignum(env, serialArray, &serialBare)) {
   4306         if (!env->ExceptionCheck()) {
   4307             jniThrowNullPointerException(env, "serial == null");
   4308         }
   4309         JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
   4310         return 0;
   4311     }
   4312 
   4313     Unique_ASN1_INTEGER serialInteger(BN_to_ASN1_INTEGER(serialBn.get(), NULL));
   4314     if (serialInteger.get() == NULL) {
   4315         JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
   4316         return 0;
   4317     }
   4318 
   4319     X509_REVOKED* revoked = NULL;
   4320     int ret = X509_CRL_get0_by_serial(x509crl, &revoked, serialInteger.get());
   4321     if (ret == 0) {
   4322         JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => none", x509crl, serialArray);
   4323         return 0;
   4324     }
   4325 
   4326     JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, serialArray, revoked);
   4327     return reinterpret_cast<uintptr_t>(revoked);
   4328 }
   4329 
   4330 
   4331 /* This appears to be missing from OpenSSL. */
   4332 #if !defined(X509_REVOKED_dup)
   4333 X509_REVOKED* X509_REVOKED_dup(X509_REVOKED* x) {
   4334     return reinterpret_cast<X509_REVOKED*>(ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), x));
   4335 }
   4336 #endif
   4337 
   4338 static jlongArray NativeCrypto_X509_CRL_get_REVOKED(JNIEnv* env, jclass, jlong x509CrlRef) {
   4339     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4340     JNI_TRACE("X509_CRL_get_REVOKED(%p)", crl);
   4341 
   4342     if (crl == NULL) {
   4343         jniThrowNullPointerException(env, "crl == null");
   4344         return NULL;
   4345     }
   4346 
   4347     STACK_OF(X509_REVOKED)* stack = X509_CRL_get_REVOKED(crl);
   4348     if (stack == NULL) {
   4349         JNI_TRACE("X509_CRL_get_REVOKED(%p) => stack is null", crl);
   4350         return NULL;
   4351     }
   4352 
   4353     size_t size = sk_X509_REVOKED_num(stack);
   4354 
   4355     ScopedLocalRef<jlongArray> revokedArray(env, env->NewLongArray(size));
   4356     ScopedLongArrayRW revoked(env, revokedArray.get());
   4357     for (size_t i = 0; i < size; i++) {
   4358         X509_REVOKED* item = reinterpret_cast<X509_REVOKED*>(sk_X509_REVOKED_value(stack, i));
   4359         revoked[i] = reinterpret_cast<uintptr_t>(X509_REVOKED_dup(item));
   4360     }
   4361 
   4362     JNI_TRACE("X509_CRL_get_REVOKED(%p) => %p [size=%d]", stack, revokedArray.get(), size);
   4363     return revokedArray.release();
   4364 }
   4365 
   4366 static jbyteArray NativeCrypto_i2d_X509_CRL(JNIEnv* env, jclass, jlong x509CrlRef) {
   4367     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4368     JNI_TRACE("i2d_X509_CRL(%p)", crl);
   4369     return ASN1ToByteArray<X509_CRL, i2d_X509_CRL>(env, crl);
   4370 }
   4371 
   4372 static void NativeCrypto_X509_CRL_free(JNIEnv* env, jclass, jlong x509CrlRef) {
   4373     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4374     JNI_TRACE("X509_CRL_free(%p)", crl);
   4375 
   4376     if (crl == NULL) {
   4377         jniThrowNullPointerException(env, "crl == null");
   4378         JNI_TRACE("X509_CRL_free(%p) => crl == null", crl);
   4379         return;
   4380     }
   4381 
   4382     X509_CRL_free(crl);
   4383 }
   4384 
   4385 static void NativeCrypto_X509_CRL_print(JNIEnv* env, jclass, jlong bioRef, jlong x509CrlRef) {
   4386     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   4387     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4388     JNI_TRACE("X509_CRL_print(%p, %p)", bio, crl);
   4389 
   4390     if (bio == NULL) {
   4391         jniThrowNullPointerException(env, "bio == null");
   4392         JNI_TRACE("X509_CRL_print(%p, %p) => bio == null", bio, crl);
   4393         return;
   4394     }
   4395 
   4396     if (crl == NULL) {
   4397         jniThrowNullPointerException(env, "crl == null");
   4398         JNI_TRACE("X509_CRL_print(%p, %p) => crl == null", bio, crl);
   4399         return;
   4400     }
   4401 
   4402     if (!X509_CRL_print(bio, crl)) {
   4403         throwExceptionIfNecessary(env, "X509_CRL_print");
   4404         JNI_TRACE("X509_CRL_print(%p, %p) => threw error", bio, crl);
   4405     } else {
   4406         JNI_TRACE("X509_CRL_print(%p, %p) => success", bio, crl);
   4407     }
   4408 }
   4409 
   4410 static jstring NativeCrypto_get_X509_CRL_sig_alg_oid(JNIEnv* env, jclass, jlong x509CrlRef) {
   4411     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4412     JNI_TRACE("get_X509_CRL_sig_alg_oid(%p)", crl);
   4413 
   4414     if (crl == NULL || crl->sig_alg == NULL) {
   4415         jniThrowNullPointerException(env, "crl == NULL || crl->sig_alg == NULL");
   4416         JNI_TRACE("get_X509_CRL_sig_alg_oid(%p) => crl == NULL", crl);
   4417         return NULL;
   4418     }
   4419 
   4420     return ASN1_OBJECT_to_OID_string(env, crl->sig_alg->algorithm);
   4421 }
   4422 
   4423 static jbyteArray NativeCrypto_get_X509_CRL_sig_alg_parameter(JNIEnv* env, jclass, jlong x509CrlRef) {
   4424     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4425     JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p)", crl);
   4426 
   4427     if (crl == NULL) {
   4428         jniThrowNullPointerException(env, "crl == null");
   4429         JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => crl == null", crl);
   4430         return NULL;
   4431     }
   4432 
   4433     if (crl->sig_alg->parameter == NULL) {
   4434         JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => null", crl);
   4435         return NULL;
   4436     }
   4437 
   4438     return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, crl->sig_alg->parameter);
   4439 }
   4440 
   4441 static jbyteArray NativeCrypto_X509_CRL_get_issuer_name(JNIEnv* env, jclass, jlong x509CrlRef) {
   4442     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4443     JNI_TRACE("X509_CRL_get_issuer_name(%p)", crl);
   4444     return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_CRL_get_issuer(crl));
   4445 }
   4446 
   4447 static long NativeCrypto_X509_CRL_get_version(JNIEnv*, jclass, jlong x509CrlRef) {
   4448     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4449     JNI_TRACE("X509_CRL_get_version(%p)", crl);
   4450 
   4451     long version = X509_CRL_get_version(crl);
   4452     JNI_TRACE("X509_CRL_get_version(%p) => %ld", crl, version);
   4453     return version;
   4454 }
   4455 
   4456 template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
   4457         X509_EXTENSION* (*get_ext_func)(T*, int)>
   4458 static X509_EXTENSION *X509Type_get_ext(JNIEnv* env, T* x509Type, jstring oidString) {
   4459     JNI_TRACE("X509Type_get_ext(%p)", x509Type);
   4460 
   4461     if (x509Type == NULL) {
   4462         jniThrowNullPointerException(env, "x509 == null");
   4463         return NULL;
   4464     }
   4465 
   4466     ScopedUtfChars oid(env, oidString);
   4467     if (oid.c_str() == NULL) {
   4468         return NULL;
   4469     }
   4470 
   4471     Unique_ASN1_OBJECT asn1(OBJ_txt2obj(oid.c_str(), 1));
   4472     if (asn1.get() == NULL) {
   4473         JNI_TRACE("X509Type_get_ext(%p, %s) => oid conversion failed", x509Type, oid.c_str());
   4474         freeOpenSslErrorState();
   4475         return NULL;
   4476     }
   4477 
   4478     int extIndex = get_ext_by_OBJ_func(x509Type, asn1.get(), -1);
   4479     if (extIndex == -1) {
   4480         JNI_TRACE("X509Type_get_ext(%p, %s) => ext not found", x509Type, oid.c_str());
   4481         return NULL;
   4482     }
   4483 
   4484     X509_EXTENSION* ext = get_ext_func(x509Type, extIndex);
   4485     JNI_TRACE("X509Type_get_ext(%p, %s) => %p", x509Type, oid.c_str(), ext);
   4486     return ext;
   4487 }
   4488 
   4489 template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
   4490         X509_EXTENSION* (*get_ext_func)(T*, int)>
   4491 static jbyteArray X509Type_get_ext_oid(JNIEnv* env, T* x509Type, jstring oidString) {
   4492     X509_EXTENSION* ext = X509Type_get_ext<T, get_ext_by_OBJ_func, get_ext_func>(env, x509Type,
   4493             oidString);
   4494     if (ext == NULL) {
   4495         JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString);
   4496         return NULL;
   4497     }
   4498 
   4499     JNI_TRACE("X509Type_get_ext_oid(%p, %p) => %p", x509Type, oidString, ext->value);
   4500     return ASN1ToByteArray<ASN1_OCTET_STRING, i2d_ASN1_OCTET_STRING>(env, ext->value);
   4501 }
   4502 
   4503 static jint NativeCrypto_X509_CRL_get_ext(JNIEnv* env, jclass, jlong x509CrlRef, jstring oid) {
   4504     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4505     JNI_TRACE("X509_CRL_get_ext(%p, %p)", crl, oid);
   4506     X509_EXTENSION* ext = X509Type_get_ext<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(
   4507             env, crl, oid);
   4508     JNI_TRACE("X509_CRL_get_ext(%p, %p) => %p", crl, oid, ext);
   4509     return reinterpret_cast<uintptr_t>(ext);
   4510 }
   4511 
   4512 static jint NativeCrypto_X509_REVOKED_get_ext(JNIEnv* env, jclass, jlong x509RevokedRef,
   4513         jstring oid) {
   4514     X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4515     JNI_TRACE("X509_REVOKED_get_ext(%p, %p)", revoked, oid);
   4516     X509_EXTENSION* ext = X509Type_get_ext<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ,
   4517             X509_REVOKED_get_ext>(env, revoked, oid);
   4518     JNI_TRACE("X509_REVOKED_get_ext(%p, %p) => %p", revoked, oid, ext);
   4519     return reinterpret_cast<uintptr_t>(ext);
   4520 }
   4521 
   4522 static jlong NativeCrypto_X509_REVOKED_dup(JNIEnv* env, jclass, jlong x509RevokedRef) {
   4523     X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4524     JNI_TRACE("X509_REVOKED_dup(%p)", revoked);
   4525 
   4526     if (revoked == NULL) {
   4527         jniThrowNullPointerException(env, "revoked == null");
   4528         JNI_TRACE("X509_REVOKED_dup(%p) => revoked == null", revoked);
   4529         return 0;
   4530     }
   4531 
   4532     X509_REVOKED* dup = X509_REVOKED_dup(revoked);
   4533     JNI_TRACE("X509_REVOKED_dup(%p) => %p", revoked, dup);
   4534     return reinterpret_cast<uintptr_t>(dup);
   4535 }
   4536 
   4537 static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass, jlong x509RevokedRef) {
   4538     X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4539     JNI_TRACE("get_X509_REVOKED_revocationDate(%p)", revoked);
   4540 
   4541     if (revoked == NULL) {
   4542         jniThrowNullPointerException(env, "revoked == null");
   4543         JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => revoked == null", revoked);
   4544         return 0;
   4545     }
   4546 
   4547     JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked, revoked->revocationDate);
   4548     return reinterpret_cast<uintptr_t>(revoked->revocationDate);
   4549 }
   4550 
   4551 #pragma GCC diagnostic push
   4552 #pragma GCC diagnostic ignored "-Wwrite-strings"
   4553 static void NativeCrypto_X509_REVOKED_print(JNIEnv* env, jclass, jlong bioRef, jlong x509RevokedRef) {
   4554     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   4555     X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4556     JNI_TRACE("X509_REVOKED_print(%p, %p)", bio, revoked);
   4557 
   4558     if (bio == NULL) {
   4559         jniThrowNullPointerException(env, "bio == null");
   4560         JNI_TRACE("X509_REVOKED_print(%p, %p) => bio == null", bio, revoked);
   4561         return;
   4562     }
   4563 
   4564     if (revoked == NULL) {
   4565         jniThrowNullPointerException(env, "revoked == null");
   4566         JNI_TRACE("X509_REVOKED_print(%p, %p) => revoked == null", bio, revoked);
   4567         return;
   4568     }
   4569 
   4570     BIO_printf(bio, "Serial Number: ");
   4571     i2a_ASN1_INTEGER(bio, revoked->serialNumber);
   4572     BIO_printf(bio, "\nRevocation Date: ");
   4573     ASN1_TIME_print(bio, revoked->revocationDate);
   4574     BIO_printf(bio, "\n");
   4575     X509V3_extensions_print(bio, "CRL entry extensions", revoked->extensions, 0, 0);
   4576 }
   4577 #pragma GCC diagnostic pop
   4578 
   4579 static jbyteArray NativeCrypto_get_X509_CRL_crl_enc(JNIEnv* env, jclass, jlong x509CrlRef) {
   4580     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4581     JNI_TRACE("get_X509_CRL_crl_enc(%p)", crl);
   4582     return ASN1ToByteArray<X509_CRL_INFO, i2d_X509_CRL_INFO>(env, crl->crl);
   4583 }
   4584 
   4585 static void NativeCrypto_X509_CRL_verify(JNIEnv* env, jclass, jlong x509CrlRef, jlong pkeyRef) {
   4586     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4587     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
   4588     JNI_TRACE("X509_CRL_verify(%p, %p)", crl, pkey);
   4589 
   4590     if (crl == NULL) {
   4591         jniThrowNullPointerException(env, "crl == null");
   4592         JNI_TRACE("X509_CRL_verify(%p, %p) => crl == null", crl, pkey);
   4593         return;
   4594     }
   4595 
   4596     if (pkey == NULL) {
   4597         jniThrowNullPointerException(env, "pkey == null");
   4598         JNI_TRACE("X509_CRL_verify(%p, %p) => pkey == null", crl, pkey);
   4599         return;
   4600     }
   4601 
   4602     if (X509_CRL_verify(crl, pkey) != 1) {
   4603         throwExceptionIfNecessary(env, "X509_CRL_verify");
   4604         JNI_TRACE("X509_CRL_verify(%p, %p) => verify failure", crl, pkey);
   4605     } else {
   4606         JNI_TRACE("X509_CRL_verify(%p, %p) => verify success", crl, pkey);
   4607     }
   4608 }
   4609 
   4610 static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
   4611     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4612     JNI_TRACE("X509_CRL_get_lastUpdate(%p)", crl);
   4613 
   4614     if (crl == NULL) {
   4615         jniThrowNullPointerException(env, "crl == null");
   4616         JNI_TRACE("X509_CRL_get_lastUpdate(%p) => crl == null", crl);
   4617         return 0;
   4618     }
   4619 
   4620     ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl);
   4621     JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate);
   4622     return reinterpret_cast<uintptr_t>(lastUpdate);
   4623 }
   4624 
   4625 static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
   4626     X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
   4627     JNI_TRACE("X509_CRL_get_nextUpdate(%p)", crl);
   4628 
   4629     if (crl == NULL) {
   4630         jniThrowNullPointerException(env, "crl == null");
   4631         JNI_TRACE("X509_CRL_get_nextUpdate(%p) => crl == null", crl);
   4632         return 0;
   4633     }
   4634 
   4635     ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl);
   4636     JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate);
   4637     return reinterpret_cast<uintptr_t>(nextUpdate);
   4638 }
   4639 
   4640 static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) {
   4641     X509_REVOKED* x509Revoked =
   4642             reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
   4643     JNI_TRACE("i2d_X509_REVOKED(%p)", x509Revoked);
   4644     return ASN1ToByteArray<X509_REVOKED, i2d_X509_REVOKED>(env, x509Revoked);
   4645 }
   4646 
   4647 static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x509ExtensionRef) {
   4648     X509_EXTENSION* ext = reinterpret_cast<X509_EXTENSION*>(static_cast<uintptr_t>(x509ExtensionRef));
   4649 
   4650     if (ext == NULL) {
   4651         jniThrowNullPointerException(env, "ext == NULL");
   4652         return 0;
   4653     }
   4654 
   4655     return X509_supported_extension(ext);
   4656 }
   4657 
   4658 static inline void get_ASN1_TIME_data(char **data, int* output, size_t len) {
   4659     char c = **data;
   4660     **data = '\0';
   4661     *data -= len;
   4662     *output = atoi(*data);
   4663     *(*data + len) = c;
   4664 }
   4665 
   4666 static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef, jobject calendar) {
   4667     ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef));
   4668     JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar);
   4669 
   4670     if (asn1Time == NULL) {
   4671         jniThrowNullPointerException(env, "asn1Time == null");
   4672         return;
   4673     }
   4674 
   4675     Unique_ASN1_GENERALIZEDTIME gen(ASN1_TIME_to_generalizedtime(asn1Time, NULL));
   4676     if (gen.get() == NULL) {
   4677         jniThrowNullPointerException(env, "asn1Time == null");
   4678         return;
   4679     }
   4680 
   4681     if (gen->length < 14 || gen->data == NULL) {
   4682         jniThrowNullPointerException(env, "gen->length < 14 || gen->data == NULL");
   4683         return;
   4684     }
   4685 
   4686     int sec, min, hour, mday, mon, year;
   4687 
   4688     char *p = (char*) &gen->data[14];
   4689 
   4690     get_ASN1_TIME_data(&p, &sec, 2);
   4691     get_ASN1_TIME_data(&p, &min, 2);
   4692     get_ASN1_TIME_data(&p, &hour, 2);
   4693     get_ASN1_TIME_data(&p, &mday, 2);
   4694     get_ASN1_TIME_data(&p, &mon, 2);
   4695     get_ASN1_TIME_data(&p, &year, 4);
   4696 
   4697     env->CallVoidMethod(calendar, calendar_setMethod, year, mon - 1, mday, hour, min, sec);
   4698 }
   4699 
   4700 static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) {
   4701     JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr);
   4702 
   4703     ScopedUtfChars oid(env, oidStr);
   4704     if (oid.c_str() == NULL) {
   4705         return NULL;
   4706     }
   4707 
   4708     JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str());
   4709 
   4710     int nid = OBJ_txt2nid(oid.c_str());
   4711     if (nid == NID_undef) {
   4712         JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str());
   4713         freeOpenSslErrorState();
   4714         return NULL;
   4715     }
   4716 
   4717     Unique_ASN1_OBJECT obj(OBJ_nid2obj(nid));
   4718     if (obj.get() == NULL) {
   4719         throwExceptionIfNecessary(env, "OBJ_nid2obj");
   4720         return NULL;
   4721     }
   4722 
   4723     ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj.get()));
   4724     JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get());
   4725     return ouputStr.release();
   4726 }
   4727 
   4728 static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) {
   4729     X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef));
   4730     unsigned long flags = static_cast<unsigned long>(jflags);
   4731     JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags);
   4732 
   4733     if (x509name == NULL) {
   4734         jniThrowNullPointerException(env, "x509name == null");
   4735         JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags);
   4736         return NULL;
   4737     }
   4738 
   4739     return X509_NAME_to_jstring(env, x509name, flags);
   4740 }
   4741 
   4742 template <typename T, T* (*d2i_func)(BIO*, T**)>
   4743 static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
   4744     BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
   4745     JNI_TRACE("d2i_ASN1Object_to_jlong(%p)", bio);
   4746 
   4747     if (bio == NULL) {
   4748         jniThrowNullPointerException(env, "bio == null");
   4749         return 0;
   4750     }
   4751 
   4752     T* x = d2i_func(bio, NULL);
   4753     if (x == NULL) {
   4754         throwExceptionIfNecessary(env, "d2i_ASN1Object_to_jlong");
   4755         return 0;
   4756     }
   4757 
   4758     return reinterpret_cast<uintptr_t>(x);
   4759 }
   4760 
   4761 static jlong NativeCrypto_d2i_X509_CRL_bio(JNIEnv* env, jclass, jlong bioRef) {
   4762     return d2i_ASN1Object_to_jlong<X509_CRL, d2i_X509_CRL_bio>(