From 83fc377e659b7d0311edaa85ba615fae176fae6c Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Tue, 23 Jul 2019 08:12:28 -0700 Subject: [PATCH 1/7] Initial attempt to move to openssl 1.1.0 --- .gitignore | 3 + build.gradle | 6 +- csrc/aes_ctr_drbg.cpp | 14 +-- csrc/aes_ctr_drbg.h | 2 +- csrc/aes_gcm.cpp | 110 +++++------------- csrc/keyutils.cpp | 67 +++++++---- csrc/keyutils.h | 60 ++++++++++ csrc/loader.cpp | 55 --------- csrc/rand.cpp | 15 +-- csrc/rdrand.cpp | 14 +-- csrc/rsa_cipher.cpp | 59 ++++++---- csrc/rsa_gen.cpp | 26 +++-- openssl.sha256 | 2 +- .../corretto/crypto/provider/AesGcmSpi.java | 6 - .../crypto/provider/test/AesTest.java | 33 ------ 15 files changed, 218 insertions(+), 254 deletions(-) diff --git a/.gitignore b/.gitignore index ef66f7ca..d2ea8484 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /build /.gradle +/.project +/.settings/ +/.vscode/ *~ diff --git a/build.gradle b/build.gradle index ad9f8ae3..8161c190 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ task getOpensslSrc { mkdir "${buildDir}/openssl/bin" exec { workingDir "${buildDir}/openssl" - commandLine 'wget', 'https://www.openssl.org/source/openssl-1.0.2r.tar.gz' + commandLine 'wget', 'https://www.openssl.org/source/openssl-1.1.1c.tar.gz' } exec { workingDir "${buildDir}/openssl" @@ -50,7 +50,7 @@ task getOpensslSrc { } exec { workingDir "${buildDir}/openssl/src" - commandLine 'tar', '-xzv', '-C', "${buildDir}/openssl/src", '--strip-components=1', '-f', "${buildDir}/openssl/openssl-1.0.2r.tar.gz" + commandLine 'tar', '-xzv', '-C', "${buildDir}/openssl/src", '--strip-components=1', '-f', "${buildDir}/openssl/openssl-1.1.1c.tar.gz" } } } @@ -61,7 +61,7 @@ task buildOpenSsl { doLast { exec { workingDir "${buildDir}/openssl/src" - commandLine './config', '-fPIC', '-ffunction-sections', '-fdata-sections', "--prefix=${buildDir}/openssl/bin", "threads", "no-zlib", "no-shared", "no-bf", "no-cast", "no-md2", "no-rc2", "no-rc4", "no-rc5", "no-jpake", "no-krb5", "no-ripemd", "no-srp", 'no-comp', 'no-hw', 'no-mdc2' + commandLine './config', '-fPIC', '-ffunction-sections', '-fdata-sections', "--prefix=${buildDir}/openssl/bin", 'no-autoload-config', 'no-capieng', 'no-cms', 'no-comp', 'no-ct', 'no-dgram', 'no-devcryptoeng', 'no-gost', 'no-hw-padlock', 'no-nextprotoneg', 'no-ocsp', 'no-psk', 'no-rfc3779', 'no-shared', 'no-sock', 'no-srp', 'no-srtp', 'threads', 'no-ts', "no-bf", "no-cast", "no-md2", "no-rc2", "no-rc4", "no-rc5", "no-srp", 'no-comp', 'no-hw', 'no-mdc2', 'enable-ec_nistp_64_gcc_128' } exec { workingDir "${buildDir}/openssl/src" diff --git a/csrc/aes_ctr_drbg.cpp b/csrc/aes_ctr_drbg.cpp index e3aeda67..0105f95b 100644 --- a/csrc/aes_ctr_drbg.cpp +++ b/csrc/aes_ctr_drbg.cpp @@ -155,7 +155,7 @@ aes_256_drbg::aes_256_drbg(const SecureBuffer& seed) no aes_256_drbg::~aes_256_drbg() noexcept { if (ctxNeedsCleanup) { - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); } if (fake_entropy) { delete[] fake_entropy; @@ -165,15 +165,15 @@ aes_256_drbg::~aes_256_drbg() noexcept { void aes_256_drbg::initialize(const SecureBuffer& seed) noexcept { static const uint8_t zero_key[DRBG_KEY_SIZE] = { 0 }; - EVP_CIPHER_CTX_init(&ctx); - if (unlikely(!EVP_EncryptInit_ex(&ctx, EVP_aes_256_ecb(), NULL, zero_key, NULL))) { + ctx = EVP_CIPHER_CTX_new(); + if (unlikely(!EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, zero_key, NULL))) { return; // failed, we'll leave it uninitialized } ctxNeedsCleanup = true; if (unlikely(!update(seed))) { - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); ctxNeedsCleanup = false; return; // leave uninitialized } @@ -186,7 +186,7 @@ void aes_256_drbg::initialize(const SecureBuffer& seed) ) { // CPU claimed to have rdseed support but failed to generate entropy; // bail out. - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); ctxNeedsCleanup = false; return; // leave uninitialized } @@ -217,7 +217,7 @@ bool aes_256_drbg::update(const SecureBuffer& seed) noe } fast_xor(temp, seed, DRBG_SEED_SIZE); - if (unlikely(!EVP_EncryptInit_ex(&ctx, EVP_aes_256_ecb(), NULL, temp, NULL))) { + if (unlikely(!EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, temp, NULL))) { return false; } memcpy(v, temp + DRBG_KEY_SIZE, DRBG_BLOCK_SIZE); @@ -259,7 +259,7 @@ bool aes_256_drbg::internalGenerateBytes(uint8_t* buf, int len) noexcept { while (generated < len) { incrementCtr(); int outLen; - if (unlikely(!EVP_EncryptUpdate(&ctx, block, &outLen, v, DRBG_BLOCK_SIZE))) { + if (unlikely(!EVP_EncryptUpdate(ctx, block, &outLen, v, DRBG_BLOCK_SIZE))) { return false; } int to_write = std::min(outLen, len - generated); diff --git a/csrc/aes_ctr_drbg.h b/csrc/aes_ctr_drbg.h index 084f3caa..0714629f 100644 --- a/csrc/aes_ctr_drbg.h +++ b/csrc/aes_ctr_drbg.h @@ -36,7 +36,7 @@ class aes_256_drbg { bool initialized; bool ctxNeedsCleanup; - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx; SecureBuffer v; // For testing purposes only int fake_entropy_pos; diff --git a/csrc/aes_gcm.cpp b/csrc/aes_gcm.cpp index 09e8e91e..f3eee4ae 100644 --- a/csrc/aes_gcm.cpp +++ b/csrc/aes_gcm.cpp @@ -10,6 +10,7 @@ #include "util.h" #include "env.h" #include "buffer.h" +#include "keyutils.h" #define NATIVE_MODE_ENCRYPT 1 #define NATIVE_MODE_DECRYPT 0 @@ -28,37 +29,9 @@ using namespace AmazonCorrettoCryptoProvider; -class EVP_CIPHER_CTX_auto : public EVP_CIPHER_CTX { - public: - EVP_CIPHER_CTX_auto() { - EVP_CIPHER_CTX_init(this); - } - ~EVP_CIPHER_CTX_auto() { - EVP_CIPHER_CTX_cleanup(this); - } -}; - -static volatile long leak_tracking_enabled = 0; -static volatile long active_instances = 0; - -struct native_context : public EVP_CIPHER_CTX { - public: - // True if this was counted to the leak tracking counters - bool leak_tracking; - - native_context() { - leak_tracking = leak_tracking_enabled; - if (unlikely(leak_tracking)) __sync_add_and_fetch(&active_instances, 1); - } - - ~native_context() { - if (unlikely(leak_tracking)) __sync_add_and_fetch(&active_instances, -1); - } -}; - static void initContext( raii_env &env, - EVP_CIPHER_CTX *ctx, + raii_cipher_ctx &ctx, jint opMode, java_buffer key, java_buffer iv @@ -127,7 +100,7 @@ static int updateLoop(raii_env &env, java_buffer out, java_buffer in, EVP_CIPHER return total_output; } -static int cryptFinish(raii_env &env, int opMode, java_buffer resultBuf, unsigned int tagLen, EVP_CIPHER_CTX *ctx) { +static int cryptFinish(raii_env &env, int opMode, java_buffer resultBuf, unsigned int tagLen, raii_cipher_ctx &ctx) { if (opMode == NATIVE_MODE_ENCRYPT && unlikely(tagLen > resultBuf.len())) { throw java_ex(EX_SHORTBUF, "No space for GCM tag"); @@ -190,16 +163,16 @@ JNIEXPORT int JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneShot java_buffer result = java_buffer::from_array(env, resultArray, resultOffset); java_buffer iv = java_buffer::from_array(env, ivArray); - native_context *ctx; + raii_cipher_ctx ctx; if (ctxPtr) { - ctx = reinterpret_cast(ctxPtr); + ctx.borrow(reinterpret_cast(ctxPtr)); jni_borrow ivBorrow(env, iv, "iv"); if (unlikely(!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, ivBorrow.data(), NATIVE_MODE_ENCRYPT))) { throw java_ex::from_openssl(EX_RUNTIME_CRYPTO, "Failed to set IV"); } } else { - ctx = new native_context(); + ctx.init(); EVP_CIPHER_CTX_init(ctx); java_buffer key = java_buffer::from_array(env, keyArray); initContext(env, ctx, NATIVE_MODE_ENCRYPT, key, iv); @@ -211,13 +184,9 @@ JNIEXPORT int JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneShot result = result.subrange(outoffset); int finalOffset = cryptFinish(env, NATIVE_MODE_ENCRYPT, result, tagLen, ctx); - if (!ctxPtr && !ctxOut) { - // Context is new and caller doesn't want it back - EVP_CIPHER_CTX_cleanup(ctx); - delete(ctx); - } else if (!ctxPtr) { + if (!ctxPtr && ctxOut) { // Context is new, but caller does want it back - jlong tmpPtr = reinterpret_cast(ctx); + jlong tmpPtr = reinterpret_cast(ctx.take()); env->SetLongArrayRegion(ctxOut, 0 /* start position */, 1 /* number of elements */, &tmpPtr); } @@ -236,7 +205,7 @@ JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp if (!ctxPtr) throw java_ex(EX_NPE, "Null context"); - native_context *ctx = reinterpret_cast(ctxPtr); + EVP_CIPHER_CTX *ctx = reinterpret_cast(ctxPtr); java_buffer iv = java_buffer::from_array(env, ivArray); jni_borrow ivBorrow(env, iv, "iv"); @@ -251,7 +220,8 @@ JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp JNIEXPORT jlong JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryptInit___3B_3B (JNIEnv *pEnv, jclass, jbyteArray keyArray, jbyteArray ivArray) { - native_context *ctx = new native_context(); + raii_cipher_ctx ctx; + ctx.init(); EVP_CIPHER_CTX_init(ctx); try { @@ -262,11 +232,8 @@ JNIEXPORT jlong JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encry initContext(env, ctx, NATIVE_MODE_ENCRYPT, key, iv); - return (jlong)ctx; + return (jlong)ctx.take(); } catch (java_ex &ex) { - EVP_CIPHER_CTX_cleanup(ctx); - delete ctx; - ex.throw_to_java(pEnv); return 0; @@ -275,10 +242,9 @@ JNIEXPORT jlong JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encry JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_releaseContext (JNIEnv *, jclass, jlong ctxPtr) { - native_context *ctx = (native_context *)ctxPtr; + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)ctxPtr; - EVP_CIPHER_CTX_cleanup(ctx); - delete ctx; + EVP_CIPHER_CTX_free(ctx); } JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryptUpdate @@ -297,7 +263,7 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp java_buffer input = java_buffer::from_array(env, inputArray, inoffset, inlen); java_buffer result = java_buffer::from_array(env, resultArray, resultOffset); - native_context *ctx = (native_context *)ctxPtr; + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)ctxPtr; return updateLoop(env, result, input, ctx); } catch (java_ex &ex) { ex.throw_to_java(pEnv); @@ -329,7 +295,7 @@ JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp raii_env env(pEnv); if (!ctxPtr) throw java_ex(EX_NPE, "Null context"); - native_context *ctx = (native_context *)ctxPtr; + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)ctxPtr; java_buffer aadBuf = java_buffer::from_array(env, input, offset, length); updateAAD_loop(env, ctx, aadBuf); @@ -350,7 +316,12 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp jint resultOffset, jint tagLen ) { - native_context *ctx = (native_context *)ctxPtr; + raii_cipher_ctx ctx; + if (releaseContext) { + ctx.move((EVP_CIPHER_CTX *)ctxPtr); + } else { + ctx.borrow((EVP_CIPHER_CTX *)ctxPtr); + } int rv = -1; try { @@ -369,20 +340,12 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_encryp rv = outoffset + finalOffset; } catch (java_ex &ex) { - if (ctx) { - EVP_CIPHER_CTX_cleanup(ctx); - delete ctx; - } + EVP_CIPHER_CTX_free(ctx.take()); ex.throw_to_java(pEnv); return -1; } - if (releaseContext) { - EVP_CIPHER_CTX_cleanup(ctx); - delete ctx; - } - return rv; } @@ -409,16 +372,16 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneSho java_buffer result = java_buffer::from_array(env, resultArray, resultOffset); java_buffer iv = java_buffer::from_array(env, ivArray); - native_context stackCtx; - native_context *ctx; + raii_cipher_ctx ctx; if (ctxPtr) { - ctx = reinterpret_cast(ctxPtr); + ctx.borrow(reinterpret_cast(ctxPtr)); + jni_borrow ivBorrow(env, iv, "iv"); if (unlikely(!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, ivBorrow.data(), NATIVE_MODE_DECRYPT))) { throw java_ex::from_openssl(EX_RUNTIME_CRYPTO, "Failed to set IV"); } } else { - ctx = (!ctxOut ? &stackCtx : new native_context()); + ctx.init(); EVP_CIPHER_CTX_init(ctx); java_buffer key = java_buffer::from_array(env, keyArray); initContext(env, ctx, NATIVE_MODE_DECRYPT, key, iv); @@ -448,12 +411,9 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneSho int outoffset = updateLoop(env, result, input, ctx); outoffset += cryptFinish(env, NATIVE_MODE_DECRYPT, result.subrange(outoffset), tagLen, ctx); - if (!ctxPtr && !ctxOut) { - // Context is new and caller doesn't want it back - EVP_CIPHER_CTX_cleanup(ctx); - } else if (!ctxPtr) { + if (!ctxPtr && ctxOut) { // Context is new, but caller does want it back - jlong tmpPtr = reinterpret_cast(ctx); + jlong tmpPtr = reinterpret_cast(ctx.take()); env->SetLongArrayRegion(ctxOut, 0, 1, &tmpPtr); } @@ -463,15 +423,3 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneSho return -1; } } - -JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_configureLeakTracking - (JNIEnv *, jclass, jboolean enable) -{ - leak_tracking_enabled = !!enable; -} - -JNIEXPORT jlong JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_getOutstandingInstanceCount - (JNIEnv *, jclass) -{ - return active_instances; -} diff --git a/csrc/keyutils.cpp b/csrc/keyutils.cpp index 51b52b6e..f757d59b 100644 --- a/csrc/keyutils.cpp +++ b/csrc/keyutils.cpp @@ -38,25 +38,48 @@ EVP_PKEY* der2EvpPrivateKey(const unsigned char* der, const int derLen, const bo } if (EVP_PKEY_base_id(result) == EVP_PKEY_RSA) { - RSA *rsa = EVP_PKEY_get1_RSA(result); + const RSA *rsa = EVP_PKEY_get0_RSA(result); if (rsa) { // We need strip zero CRT values which can confuse OpenSSL - BN_null_if_zero(rsa->e); - BN_null_if_zero(rsa->p); - BN_null_if_zero(rsa->q); - BN_null_if_zero(rsa->dmp1); - BN_null_if_zero(rsa->dmq1); - BN_null_if_zero(rsa->iqmp); - - if (rsa->e) { - RSA_blinding_on(rsa, NULL); - } else { - RSA_blinding_off(rsa); + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *dmp1; + const BIGNUM *dmq1; + const BIGNUM *iqmp; + bool need_rebuild = false; + + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + if (e && BN_is_zero(e)) { + need_rebuild = true; + } else if (p && BN_is_zero(p)) { + need_rebuild = true; + } else if (q && BN_is_zero(q)) { + need_rebuild = true; + } else if (dmp1 && BN_is_zero(dmp1)) { + need_rebuild = true; + } else if (dmq1 && BN_is_zero(dmq1)) { + need_rebuild = true; + } else if (iqmp && BN_is_zero(iqmp)) { + need_rebuild = true; } - // get1_RSA incremented the key's reference count, so we need to free to decrement it again - RSA_free(rsa); + if (need_rebuild) { + // This key likely only has (n, d) set. Very weird, but it happens in java sometimes. + RSA *nulled_rsa = RSA_new(); + + if (!RSA_set0_key(nulled_rsa, BN_dup(n), BN_dup(e), BN_dup(d))) { + throw_openssl(javaExceptionClass, "Unable to set RSA key parameters"); + } + EVP_PKEY_set1_RSA(result, nulled_rsa); + RSA_free(nulled_rsa); // Decrement reference counter + RSA_blinding_off(nulled_rsa); + } } } @@ -88,26 +111,28 @@ bool checkKey(EVP_PKEY* key) { int keyType = EVP_PKEY_base_id(key); bool result = false; - RSA* rsaKey; - EC_KEY* ecKey; + const RSA* rsaKey; + const BIGNUM *p; + const BIGNUM *q; + const EC_KEY* ecKey; switch (keyType) { case EVP_PKEY_RSA: - rsaKey = EVP_PKEY_get1_RSA(key); + rsaKey = EVP_PKEY_get0_RSA(key); + RSA_get0_factors(rsaKey, &p, &q); // RSA_check_key only works when sufficient private values are set - if (rsaKey->p && !BN_is_zero(rsaKey->p) && rsaKey->q && !BN_is_zero(rsaKey->q)) { + if (p && !BN_is_zero(p) && q && !BN_is_zero(q)) { result = RSA_check_key(rsaKey) == 1; } else { // We don't have enough information to actually check the key result = true; } - RSA_free(rsaKey); + break; case EVP_PKEY_EC: - ecKey = EVP_PKEY_get1_EC_KEY(key); + ecKey = EVP_PKEY_get0_EC_KEY(key); result = EC_KEY_check_key(ecKey) == 1; - EC_KEY_free(ecKey); break; default: // Keys we can't check, we just claim are fine, because there is nothing else we can do. diff --git a/csrc/keyutils.h b/csrc/keyutils.h index 2c8e620a..88fb0687 100644 --- a/csrc/keyutils.h +++ b/csrc/keyutils.h @@ -90,6 +90,66 @@ EVP_PKEY* der2EvpPrivateKey(const unsigned char* der, const int derLen, const bo EVP_PKEY* der2EvpPublicKey(const unsigned char* der, const int derLen, const char* javaExceptionClass); bool checkKey(EVP_PKEY* key); +class raii_cipher_ctx { + private: + EVP_CIPHER_CTX* m_ctx; + bool m_owning; + + public: + raii_cipher_ctx() + : m_ctx(nullptr), m_owning(false) + { + } + + void clean() { + if (m_ctx && m_owning) { + EVP_CIPHER_CTX_free(m_ctx); + } + } + + ~raii_cipher_ctx() { + clean(); + } + + void init() { + move(EVP_CIPHER_CTX_new()); + } + + void borrow(EVP_CIPHER_CTX *ctx) { + clean(); + m_owning = false; + m_ctx = ctx; + } + + void move(EVP_CIPHER_CTX *ctx) { + clean(); + m_owning = true; + m_ctx = ctx; + } + + operator EVP_CIPHER_CTX*() { + return m_ctx; + } + + operator const EVP_CIPHER_CTX*() const { + return m_ctx; + } + + EVP_CIPHER_CTX& operator*() { + return *m_ctx; + } + + const EVP_CIPHER_CTX& operator*() const { + return *m_ctx; + } + + EVP_CIPHER_CTX* take() { + EVP_CIPHER_CTX* result = m_ctx; + m_ctx = nullptr; + return result; + } +}; + } #endif diff --git a/csrc/loader.cpp b/csrc/loader.cpp index 589d263f..4f29b90a 100644 --- a/csrc/loader.cpp +++ b/csrc/loader.cpp @@ -25,55 +25,7 @@ using namespace AmazonCorrettoCryptoProvider; namespace { - -static pthread_mutex_t *lock_cs; -static int numLocks; - -void locking_callback(int mode, int type, const char* file, int line) { - if (mode & CRYPTO_LOCK) { - if (pthread_mutex_lock(&(lock_cs[type])) != 0) { - abort(); - } - } else { - if (pthread_mutex_unlock(&(lock_cs[type])) != 0) { - abort(); - } - } -} - -unsigned long thread_id_callback() { - return (unsigned long) pthread_self(); -} - void initialize() { - // While there is a chance of bad threading, this is the best we can do - if (CRYPTO_get_locking_callback() == NULL) { - // No locking enabled, register our own - numLocks = CRYPTO_num_locks(); - lock_cs = (pthread_mutex_t*) OPENSSL_malloc(numLocks * sizeof(pthread_mutex_t)); - if (!lock_cs) { - // We can't actually throw an exception here - // TODO: Report this in a safe manner - fprintf(stderr, "Unable to allocate memory for locks\n"); - abort(); - } - // lock_cs is purposefully leaked since we will need it for as long as this application runs - // and we do not have a reliable way to clean it up upon termination - - for (int x = 0; x < numLocks; x++) { - pthread_mutex_init(&lock_cs[x], NULL); - } - - // primary callback set - CRYPTO_set_locking_callback(locking_callback); - // Take the lock and set the threadid callback - CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); - - CRYPTO_set_id_callback(thread_id_callback); - - // Release the lock - CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); - } ERR_load_crypto_strings(); OpenSSL_add_all_digests(); @@ -91,13 +43,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_VERSION_1_4; } -void JNI_OnUnload(JavaVM *vm, void *reserved) { - for (int x = 0; x < numLocks; x++) { - pthread_mutex_destroy(&lock_cs[x]); - OPENSSL_free(lock_cs); - } -} - JNIEXPORT jstring JNICALL Java_com_amazon_corretto_crypto_provider_Loader_getNativeLibraryVersion( JNIEnv *pEnv, jclass diff --git a/csrc/rand.cpp b/csrc/rand.cpp index 8c702bc4..80d20656 100644 --- a/csrc/rand.cpp +++ b/csrc/rand.cpp @@ -18,9 +18,9 @@ using namespace AmazonCorrettoCryptoProvider; namespace { -static void seed(const void *buf, int num); +static int seed(const void *buf, int num); static int bytes(unsigned char *buf, int num); -static void add(const void *buf, int num, double entropy); +static int add(const void *buf, int num, double entropy); static int pseudorand(unsigned char *buf, int num); static void cleanup(); static int status(); @@ -65,14 +65,14 @@ int bytes(unsigned char *buf, int num) { } } -void add(const void *buf, int num, double entropy) { - seed(buf, num); +int add(const void *buf, int num, double entropy) { + return seed(buf, num); } -void seed(const void *buf, int num) { +int seed(const void *buf, int num) { pthread_lock_auto lock(&drbg_lock); if (!drbg || !healthy) { - return; + return 0; } SecureBuffer seed; @@ -82,11 +82,12 @@ void seed(const void *buf, int num) { memcpy(seed.buf, start, len); if (!drbg->reseed(seed)) { healthy = false; - return; + return 0; } start += len; num -= len; } + return 1; } int status() { diff --git a/csrc/rdrand.cpp b/csrc/rdrand.cpp index 24032738..6fe216a4 100644 --- a/csrc/rdrand.cpp +++ b/csrc/rdrand.cpp @@ -7,6 +7,7 @@ #include "buffer.h" #include "generated-headers.h" #include "rdrand.h" +#include "keyutils.h" #include #define DEFAULT_RETRY_COUNT 100 @@ -182,8 +183,9 @@ bool rdseed_fallback(uint64_t *dest) { bool success = false; int blockindex = 0, rdrand_retries_remain = 100; - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); + raii_cipher_ctx ctx; + ctx.init(); + EVP_CIPHER_CTX_init(ctx); for (blockindex = 0; blockindex < (512 + 2) * 2; blockindex++) { // First, retry rdseed. Maybe it'll work this time? @@ -216,17 +218,17 @@ bool rdseed_fallback(uint64_t *dest) { memcpy(iv, inbuf, 16); memset(inbuf, 0, 16); - if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv)) { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) { goto out; } - if (!EVP_CIPHER_CTX_set_padding(&ctx, 0)) { + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) { goto out; } break; default: // all other blocks are data to pump through - if (!EVP_EncryptUpdate(&ctx, outbuf, &outl, inbuf, sizeof(inbuf))) { + if (!EVP_EncryptUpdate(ctx, outbuf, &outl, inbuf, sizeof(inbuf))) { goto out; } @@ -260,8 +262,6 @@ bool rdseed_fallback(uint64_t *dest) { if (!success) *dest = 0; - EVP_CIPHER_CTX_cleanup(&ctx); - return success; } diff --git a/csrc/rsa_cipher.cpp b/csrc/rsa_cipher.cpp index 2016fda6..310e47a0 100644 --- a/csrc/rsa_cipher.cpp +++ b/csrc/rsa_cipher.cpp @@ -76,18 +76,43 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_RsaCipher_cipher RSA_auto backing; // Used for auto-cleanup RSA* r = (RSA *) backing; + BIGNUM *bn_n; + BIGNUM *bn_e; + BIGNUM *bn_d; + BIGNUM *bn_p; + BIGNUM *bn_q; + BIGNUM *bn_dmp1; + BIGNUM *bn_dmq1; + BIGNUM *bn_iqmp; switch (handleMode) { case com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_IGNORE: // fallthrough case com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_CREATE: - r->n = opt_jarr2bn(env, n); - r->e = opt_jarr2bn(env, e); - r->d = opt_jarr2bn(env, d); - r->p = opt_jarr2bn(env, p); - r->q = opt_jarr2bn(env, q); - r->dmp1 = opt_jarr2bn(env, dmp1); - r->dmq1 = opt_jarr2bn(env, dmq1); - r->iqmp = opt_jarr2bn(env, iqmp); + bn_n = opt_jarr2bn(env, n); + bn_e = opt_jarr2bn(env, e); + bn_d = opt_jarr2bn(env, d); + bn_p = opt_jarr2bn(env, p); + bn_q = opt_jarr2bn(env, q); + bn_dmp1 = opt_jarr2bn(env, dmp1); + bn_dmq1 = opt_jarr2bn(env, dmq1); + bn_iqmp = opt_jarr2bn(env, iqmp); + + if (!bn_e) { + bn_e = BN_new(); + } + if (!bn_d) { + bn_d = BN_new(); + } + if (!RSA_set0_key(r, bn_n, bn_e, bn_d)) { + throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key parameters"); + } + if (p && q && !RSA_set0_factors(r, bn_p, bn_q)) { + throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key factors"); + } + + if (dmp1 && dmq1 && iqmp && !RSA_set0_crt_params(r, bn_dmp1, bn_dmq1, bn_iqmp)) { + throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key crt_params"); + } // If it is a private key, we check it for consistency, if possible and requested if (checkPrivateKey && d != NULL && p != NULL && q != NULL) { if (RSA_check_key(r) != 1) { @@ -154,23 +179,7 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_RsaCipher_cipher } if (len < 0) { - unsigned long errCode = drainOpensslErrors(); - char errBuf[120]; - ERR_error_string_n(errCode, errBuf, sizeof(errBuf)); - - // Ensure the buffer is null-terminated even if the message is truncated. - errBuf[sizeof(errBuf)-1] = 0; - - if (errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PUBLIC_ENCRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS) - || errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PRIVATE_DECRYPT, RSA_R_DATA_TOO_LARGE_FOR_MODULUS) - || errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2, RSA_R_PKCS_DECODING_ERROR) - || errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PRIVATE_DECRYPT, RSA_R_PADDING_CHECK_FAILED) - || errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_PADDING_CHECK_FAILED) - || errCode == ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_OAEP_DECODING_ERROR)) { - throw_java_ex(EX_BADPADDING, errBuf); - } else { - throw_java_ex(EX_RUNTIME_CRYPTO, errBuf); - } + throw_openssl(EX_BADPADDING, "Unknown error"); } } if (handleMode == com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_CREATE) { diff --git a/csrc/rsa_gen.cpp b/csrc/rsa_gen.cpp index 8c8cbe36..5c748f65 100644 --- a/csrc/rsa_gen.cpp +++ b/csrc/rsa_gen.cpp @@ -42,13 +42,25 @@ JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_RsaGen_generate( throw_openssl("Key failed consistency check"); } - bn2jarr(env, modulusOut, r->n); - bn2jarr(env, privExpOut, r->d); - bn2jarr(env, primePOut, r->p); - bn2jarr(env, primeQOut, r->q); - bn2jarr(env, dmPOut, r->dmp1); - bn2jarr(env, dmQOut, r->dmq1); - bn2jarr(env, coefOut, r->iqmp); + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *dmp1; + const BIGNUM *dmq1; + const BIGNUM *iqmp; + RSA_get0_key(r, &n, &e, &d); + RSA_get0_factors(r, &p, &q); + RSA_get0_crt_params(r, &dmp1, &dmq1, &iqmp); + + bn2jarr(env, modulusOut, n); + bn2jarr(env, privExpOut, d); + bn2jarr(env, primePOut, p); + bn2jarr(env, primeQOut, q); + bn2jarr(env, dmPOut, dmp1); + bn2jarr(env, dmQOut, dmq1); + bn2jarr(env, coefOut, iqmp); } catch (java_ex &ex) { ex.throw_to_java(pEnv); } diff --git a/openssl.sha256 b/openssl.sha256 index efcd9db6..56356619 100644 --- a/openssl.sha256 +++ b/openssl.sha256 @@ -1 +1 @@ -ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6 openssl-1.0.2r.tar.gz +f6fb3079ad15076154eda9413fed42877d668e7069d9b87396d0804fdb3f4c90 openssl-1.1.1c.tar.gz diff --git a/src/com/amazon/corretto/crypto/provider/AesGcmSpi.java b/src/com/amazon/corretto/crypto/provider/AesGcmSpi.java index a89c2dd0..333905b1 100644 --- a/src/com/amazon/corretto/crypto/provider/AesGcmSpi.java +++ b/src/com/amazon/corretto/crypto/provider/AesGcmSpi.java @@ -191,12 +191,6 @@ private static native int encryptDoFinal( */ private static native void releaseContext(long ptr); - // Exposed for testing - static native void configureLeakTracking(boolean enable); - static native long getOutstandingInstanceCount(); - - - private static final int BLOCK_SIZE = 128 / 8; private NativeResource context = null; diff --git a/tst/com/amazon/corretto/crypto/provider/test/AesTest.java b/tst/com/amazon/corretto/crypto/provider/test/AesTest.java index a82fc96f..534bf3be 100644 --- a/tst/com/amazon/corretto/crypto/provider/test/AesTest.java +++ b/tst/com/amazon/corretto/crypto/provider/test/AesTest.java @@ -723,31 +723,6 @@ public void testUninitializedCipher() throws Throwable { assertThrows(IllegalStateException.class, () -> sneakyInvoke(spi, "engineGetOutputSize", 0)); } - @Test - public void testFinalizer() throws Throwable { - sneakyInvoke(SPI_CLASS, "configureLeakTracking", true); - - System.gc(); - System.gc(); - - spinAssertEquals(0, this::getOutstandingInstanceCount); - - Cipher c = Cipher.getInstance(ALGO_NAME, PROVIDER_AMAZON); - c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, new byte[128]), rnd); - - c.update(new byte[16]); - - spinAssertEquals(1, this::getOutstandingInstanceCount); - - c = null; - - System.gc(); - - spinAssertEquals(0, this::getOutstandingInstanceCount); - - sneakyInvoke(SPI_CLASS, "configureLeakTracking", false); - } - @Test public void testShortArrays() throws Throwable { Cipher c = Cipher.getInstance(ALGO_NAME, PROVIDER_AMAZON); @@ -867,14 +842,6 @@ public void safeReuse() throws Throwable { assertArrayEquals(plaintext2, c.doFinal(ciphertext2)); } - private long getOutstandingInstanceCount() { - try { - return (Long) sneakyInvoke(SPI_CLASS, "getOutstandingInstanceCount"); - } catch (final Throwable ex) { - throw new RuntimeException(ex); - } - } - private void spinAssertEquals(long expected, LongSupplier actual) throws InterruptedException { long maxCount = 10; From f7e027dad6afbcad4935bcf5f6721d6fba0c8405 Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Wed, 24 Jul 2019 16:39:19 +0000 Subject: [PATCH 2/7] Add explicit pthread requirement --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d95d011b..2a6fa56c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,9 @@ endif() find_package(JNI REQUIRED) include(FindOpenSSL) +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + set(BUILD_CLASSPATH "" CACHE STRING "Classpath to JARs to be included at build time") set(TEST_CLASSPATH "" CACHE STRING "Classpath to be included at test build and test execution time") set(SIGNED_JAR "" CACHE STRING "Path to a pre-signed JAR file, to be used instead of compiling the java source") @@ -506,6 +509,9 @@ string(STRIP "${PROBED_LINKED_FLAGS}" PROBED_LINKED_FLAGS) MESSAGE(STATUS "probed flags ${PROBED_LINKED_FLAGS}") target_link_libraries(amazonCorrettoCryptoProvider ${PROBED_LINKED_FLAGS}) +# Add pthread support +target_link_libraries(amazonCorrettoCryptoProvider Threads::Threads) + ## Tests add_jar( tests-code-jar From 14b3e08f67d696bf5fb727ab0219b04e94dda730 Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Wed, 11 Sep 2019 12:29:28 -0700 Subject: [PATCH 3/7] Bump version to 1.2.0 --- CHANGELOG.md | 5 +++++ README.md | 2 +- build.gradle | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 978d8b46..4cb32f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.2.0 + +### Improvements +* Now uses [OpenSSL 1.1.1.c](https://www.openssl.org/source/openssl-1.1.1c.tar.gz) + ## 1.1.1 ### Patches diff --git a/README.md b/README.md index 6d1a3d2a..4803e33c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Amazon Corretto Crypto Provider -The Amazon Corretto Crypto Provider (ACCP) is a collection of high-performance cryptographic implementations exposed via the standard [JCA/JCE](https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html) interfaces. This means that it can be used as a drop in replacement for many different Java applications. Currently algorithms are primarily backed by OpenSSL's implementations but this may change in the future. +The Amazon Corretto Crypto Provider (ACCP) is a collection of high-performance cryptographic implementations exposed via the standard [JCA/JCE](https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html) interfaces. This means that it can be used as a drop in replacement for many different Java applications. Currently algorithms are primarily backed by OpenSSL's implementations (1.1.1c) but this may change in the future. ## Build Status Please be aware that "Overkill" tests are known to be flakey diff --git a/build.gradle b/build.gradle index 8161c190..f53c7f5a 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group = 'software.amazon.cryptools' -version = '1.1.1' +version = '1.2.0' configurations { jacocoAgent From a5f369bdd3efd43dc51ca0b466532bb499b34977 Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Wed, 2 Oct 2019 15:42:07 -0700 Subject: [PATCH 4/7] Move to openssl 1.1.1d --- CHANGELOG.md | 2 +- README.md | 2 +- build.gradle | 6 +++--- openssl.sha256 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb32f67..8cdf917a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 1.2.0 ### Improvements -* Now uses [OpenSSL 1.1.1.c](https://www.openssl.org/source/openssl-1.1.1c.tar.gz) +* Now uses [OpenSSL 1.1.1.d](https://www.openssl.org/source/openssl-1.1.1d.tar.gz) ## 1.1.1 diff --git a/README.md b/README.md index 38eeca1b..4cf6398c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Amazon Corretto Crypto Provider -The Amazon Corretto Crypto Provider (ACCP) is a collection of high-performance cryptographic implementations exposed via the standard [JCA/JCE](https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html) interfaces. This means that it can be used as a drop in replacement for many different Java applications. Currently algorithms are primarily backed by OpenSSL's implementations (1.1.1c) but this may change in the future. +The Amazon Corretto Crypto Provider (ACCP) is a collection of high-performance cryptographic implementations exposed via the standard [JCA/JCE](https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html) interfaces. This means that it can be used as a drop in replacement for many different Java applications. Currently algorithms are primarily backed by OpenSSL's implementations (1.1.1d) but this may change in the future. ## Build Status Please be aware that "Overkill" tests are known to be flakey diff --git a/build.gradle b/build.gradle index f53c7f5a..2766373b 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ task getOpensslSrc { mkdir "${buildDir}/openssl/bin" exec { workingDir "${buildDir}/openssl" - commandLine 'wget', 'https://www.openssl.org/source/openssl-1.1.1c.tar.gz' + commandLine 'wget', 'https://www.openssl.org/source/openssl-1.1.1d.tar.gz' } exec { workingDir "${buildDir}/openssl" @@ -50,7 +50,7 @@ task getOpensslSrc { } exec { workingDir "${buildDir}/openssl/src" - commandLine 'tar', '-xzv', '-C', "${buildDir}/openssl/src", '--strip-components=1', '-f', "${buildDir}/openssl/openssl-1.1.1c.tar.gz" + commandLine 'tar', '-xzv', '-C', "${buildDir}/openssl/src", '--strip-components=1', '-f', "${buildDir}/openssl/openssl-1.1.1d.tar.gz" } } } @@ -61,7 +61,7 @@ task buildOpenSsl { doLast { exec { workingDir "${buildDir}/openssl/src" - commandLine './config', '-fPIC', '-ffunction-sections', '-fdata-sections', "--prefix=${buildDir}/openssl/bin", 'no-autoload-config', 'no-capieng', 'no-cms', 'no-comp', 'no-ct', 'no-dgram', 'no-devcryptoeng', 'no-gost', 'no-hw-padlock', 'no-nextprotoneg', 'no-ocsp', 'no-psk', 'no-rfc3779', 'no-shared', 'no-sock', 'no-srp', 'no-srtp', 'threads', 'no-ts', "no-bf", "no-cast", "no-md2", "no-rc2", "no-rc4", "no-rc5", "no-srp", 'no-comp', 'no-hw', 'no-mdc2', 'enable-ec_nistp_64_gcc_128' + commandLine './config', '-fPIC', '-ffunction-sections', '-fdata-sections', "--prefix=${buildDir}/openssl/bin", 'no-autoload-config', 'no-capieng', 'no-cms', 'no-comp', 'no-ct', 'no-dgram', 'no-devcryptoeng', 'no-gost', 'no-hw-padlock', 'no-nextprotoneg', 'no-ocsp', 'no-psk', 'no-rfc3779', 'no-shared', 'no-sock', 'no-srp', 'no-srtp', 'threads', 'no-ts', "no-bf", "no-cast", "no-md2", "no-rc2", "no-rc4", "no-rc5", "no-srp", 'no-comp', 'no-hw', 'no-mdc2' } exec { workingDir "${buildDir}/openssl/src" diff --git a/openssl.sha256 b/openssl.sha256 index 56356619..0b61d78d 100644 --- a/openssl.sha256 +++ b/openssl.sha256 @@ -1 +1 @@ -f6fb3079ad15076154eda9413fed42877d668e7069d9b87396d0804fdb3f4c90 openssl-1.1.1c.tar.gz +1e3a91bc1f9dfce01af26026f856e064eab4c8ee0a8f457b5ae30b40b8b711f2 openssl-1.1.1d.tar.gz From ffa6fc7812c73f3ae15de167508a3bd5cba2313e Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Mon, 14 Oct 2019 13:24:28 -0700 Subject: [PATCH 5/7] Ignore IntelliJ files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d2ea8484..ac46a1a6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ /.settings/ /.vscode/ *~ +*.ipr +*.iws From 904d9247f9ae53405f469a8988ed387ab166af85 Mon Sep 17 00:00:00 2001 From: Greg Rubin Date: Mon, 14 Oct 2019 13:25:54 -0700 Subject: [PATCH 6/7] Fix possible memory leak in rsa_cipher.cpp --- csrc/bn.h | 14 +++++++++ csrc/rsa_cipher.cpp | 72 ++++++++++++++++++--------------------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/csrc/bn.h b/csrc/bn.h index ecd43def..ce330450 100644 --- a/csrc/bn.h +++ b/csrc/bn.h @@ -71,6 +71,20 @@ class BigNumObj { return m_pBN; } + void releaseOwnership() { + m_pBN = NULL; + } + + static BigNumObj fromJavaArray(raii_env &env, jbyteArray array) { + BigNumObj result; + + if (array) { + result.ensure_init(); + jarr2bn(env, array, result.m_pBN); + } + return result; + } + #ifdef HAVE_CPP11 BigNumObj(const BigNumObj &) = delete; BigNumObj &operator=(const BigNumObj &) = delete; diff --git a/csrc/rsa_cipher.cpp b/csrc/rsa_cipher.cpp index 310e47a0..47be8dfd 100644 --- a/csrc/rsa_cipher.cpp +++ b/csrc/rsa_cipher.cpp @@ -12,26 +12,6 @@ using namespace AmazonCorrettoCryptoProvider; -namespace { - -BIGNUM *opt_jarr2bn(raii_env &env, jbyteArray array) { - BIGNUM *ret = NULL; - if (array) { - ret = BN_new(); - - try { - jarr2bn(env, array, ret); - } catch (...) { - BN_clear_free(ret); - throw; - } - } - - return ret; -} - -} // anonymous namespace - /* * Class: com_amazon_corretto_crypto_provider_RsaCipher * Method: releaseNativeKey @@ -70,49 +50,52 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_RsaCipher_cipher ) { - + try { raii_env env(pEnv); RSA_auto backing; // Used for auto-cleanup RSA* r = (RSA *) backing; - BIGNUM *bn_n; - BIGNUM *bn_e; - BIGNUM *bn_d; - BIGNUM *bn_p; - BIGNUM *bn_q; - BIGNUM *bn_dmp1; - BIGNUM *bn_dmq1; - BIGNUM *bn_iqmp; switch (handleMode) { case com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_IGNORE: // fallthrough case com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_CREATE: - bn_n = opt_jarr2bn(env, n); - bn_e = opt_jarr2bn(env, e); - bn_d = opt_jarr2bn(env, d); - bn_p = opt_jarr2bn(env, p); - bn_q = opt_jarr2bn(env, q); - bn_dmp1 = opt_jarr2bn(env, dmp1); - bn_dmq1 = opt_jarr2bn(env, dmq1); - bn_iqmp = opt_jarr2bn(env, iqmp); - - if (!bn_e) { - bn_e = BN_new(); - } - if (!bn_d) { - bn_d = BN_new(); - } + { + // When used with a set0 method, memory ownership transfers to the receiving object. + // Thus, after successful ownership transfer, we release ownership of the BIGNUMs. + // Once the RSA key owns them, since it is is an RSA_auto class, it cleans itself + // up if it remains on the stack. + BigNumObj bn_n = BigNumObj::fromJavaArray(env, n); + BigNumObj bn_e = BigNumObj::fromJavaArray(env, e); + BigNumObj bn_d = BigNumObj::fromJavaArray(env, d); + BigNumObj bn_p = BigNumObj::fromJavaArray(env, p); + BigNumObj bn_q = BigNumObj::fromJavaArray(env, q); + BigNumObj bn_dmp1 = BigNumObj::fromJavaArray(env, dmp1); + BigNumObj bn_dmq1 = BigNumObj::fromJavaArray(env, dmq1); + BigNumObj bn_iqmp = BigNumObj::fromJavaArray(env, iqmp); + if (!RSA_set0_key(r, bn_n, bn_e, bn_d)) { throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key parameters"); + } else { + bn_n.releaseOwnership(); + bn_e.releaseOwnership(); + bn_d.releaseOwnership(); } if (p && q && !RSA_set0_factors(r, bn_p, bn_q)) { throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key factors"); + } else { + bn_p.releaseOwnership(); + bn_q.releaseOwnership(); } if (dmp1 && dmq1 && iqmp && !RSA_set0_crt_params(r, bn_dmp1, bn_dmq1, bn_iqmp)) { throw_openssl(EX_RUNTIME_CRYPTO, "Unable to set key crt_params"); + } else { + bn_dmp1.releaseOwnership(); + bn_dmq1.releaseOwnership(); + bn_iqmp.releaseOwnership(); } + // If it is a private key, we check it for consistency, if possible and requested if (checkPrivateKey && d != NULL && p != NULL && q != NULL) { if (RSA_check_key(r) != 1) { @@ -132,6 +115,7 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_RsaCipher_cipher RSA_blinding_off(r); } break; + } case com_amazon_corretto_crypto_provider_RsaCipher_HANDLE_USAGE_USE: jlong tmpPtr; env->GetLongArrayRegion(keyHandle, 0, 1, &tmpPtr); From f88755811167362414f59d1029256a47b521038e Mon Sep 17 00:00:00 2001 From: SalusaSecondus Date: Tue, 15 Oct 2019 12:33:10 -0700 Subject: [PATCH 7/7] Remove duplicate word in comment Co-Authored-By: seebees --- csrc/rsa_cipher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csrc/rsa_cipher.cpp b/csrc/rsa_cipher.cpp index 47be8dfd..213581d0 100644 --- a/csrc/rsa_cipher.cpp +++ b/csrc/rsa_cipher.cpp @@ -62,7 +62,7 @@ JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_RsaCipher_cipher { // When used with a set0 method, memory ownership transfers to the receiving object. // Thus, after successful ownership transfer, we release ownership of the BIGNUMs. - // Once the RSA key owns them, since it is is an RSA_auto class, it cleans itself + // Once the RSA key owns them, since it is an RSA_auto class, it cleans itself // up if it remains on the stack. BigNumObj bn_n = BigNumObj::fromJavaArray(env, n); BigNumObj bn_e = BigNumObj::fromJavaArray(env, e);