From 97502189ba19e1f15540aab7296046265c14f50a Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Fri, 14 Jun 2024 09:11:42 -0400 Subject: [PATCH] Use native cryptography where available (#830) * Only register crypto Java callbacks if mongocrypt_is_crypto_available returns false * Package crypto-enabled shared libraries on Mac and Windows * Continue to package crypto-disabled shared libraries on Linux due to OpenSSL incompatibilities. Applications can force use of a crypto-enabled shared library by manually installing it in the system path or else specify the path via jna.library.path system variable. JAVA-5306 --- bindings/java/mongocrypt/build.gradle.kts | 2 +- .../java/com/mongodb/crypt/capi/CAPI.java | 11 ++++ .../mongodb/crypt/capi/MongoCryptImpl.java | 53 ++++++++++++------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/bindings/java/mongocrypt/build.gradle.kts b/bindings/java/mongocrypt/build.gradle.kts index 2d60d57e1..2a99d66f4 100644 --- a/bindings/java/mongocrypt/build.gradle.kts +++ b/bindings/java/mongocrypt/build.gradle.kts @@ -139,7 +139,7 @@ tasks.register("unzipJava") { outputs.upToDateWhen { false } from(tarTree(resources.gzip("${jnaDownloadsDir}/libmongocrypt-java.tar.gz"))) include(jnaMapping.keys.flatMap { - listOf("${it}/nocrypto/**/libmongocrypt.so", "${it}/nocrypto/**/libmongocrypt.dylib", "${it}/nocrypto/**/mongocrypt.dll" ) + listOf("${it}/nocrypto/**/libmongocrypt.so", "${it}/lib/**/libmongocrypt.dylib", "${it}/bin/**/mongocrypt.dll" ) }) eachFile { path = "${jnaMapping[path.substringBefore("/")]}/${name}" diff --git a/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java b/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java index c6a3b312d..75c8e7c9f 100644 --- a/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java +++ b/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java @@ -624,6 +624,17 @@ public interface mongocrypt_random_fn extends Callback { public static native boolean mongocrypt_status(mongocrypt_t crypt, mongocrypt_status_t status); + /** + * Returns true if libmongocrypt was built with native crypto support. + * + *

+ * If libmongocrypt was not built with native crypto support, setting crypto hooks is required. + *

+ * + * @return true if libmongocrypt was built with native crypto support + */ + public static native boolean + mongocrypt_is_crypto_available(); /** * Destroy the @ref mongocrypt_t object. diff --git a/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java b/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java index 7cf6f0d0e..2132f3c68 100644 --- a/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java +++ b/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java @@ -57,6 +57,7 @@ import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_query_type; import static com.mongodb.crypt.capi.CAPI.mongocrypt_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_init; +import static com.mongodb.crypt.capi.CAPI.mongocrypt_is_crypto_available; import static com.mongodb.crypt.capi.CAPI.mongocrypt_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_aes_256_ctr; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_append_crypt_shared_lib_search_path; @@ -118,25 +119,39 @@ class MongoCryptImpl implements MongoCrypt { configure(() -> mongocrypt_setopt_log_handler(wrapped, logCallback, null)); - // We specify NoPadding here because the underlying C library is responsible for padding prior - // to executing the callback - aesCBC256EncryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.ENCRYPT_MODE); - aesCBC256DecryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.DECRYPT_MODE); - aesCTR256EncryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.ENCRYPT_MODE); - aesCTR256DecryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.DECRYPT_MODE); - - hmacSha512Callback = new MacCallback("HmacSHA512"); - hmacSha256Callback = new MacCallback("HmacSHA256"); - sha256Callback = new MessageDigestCallback("SHA-256"); - secureRandomCallback = new SecureRandomCallback(new SecureRandom()); - - configure(() -> mongocrypt_setopt_crypto_hooks(wrapped, aesCBC256EncryptCallback, aesCBC256DecryptCallback, - secureRandomCallback, hmacSha512Callback, hmacSha256Callback, - sha256Callback, null)); - - signingRSAESPKCSCallback = new SigningRSAESPKCSCallback(); - configure(() -> mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(wrapped, signingRSAESPKCSCallback, null)); - configure(() -> mongocrypt_setopt_aes_256_ctr(wrapped, aesCTR256EncryptCallback, aesCTR256DecryptCallback, null)); + if (mongocrypt_is_crypto_available()) { + LOGGER.debug("libmongocrypt is compiled with cryptography support, so not registering Java callbacks"); + aesCBC256EncryptCallback = null; + aesCBC256DecryptCallback = null; + aesCTR256EncryptCallback = null; + aesCTR256DecryptCallback = null; + hmacSha512Callback = null; + hmacSha256Callback = null; + sha256Callback = null; + secureRandomCallback = null; + signingRSAESPKCSCallback = null; + } else { + LOGGER.debug("libmongocrypt is compiled without cryptography support, so registering Java callbacks"); + // We specify NoPadding here because the underlying C library is responsible for padding prior + // to executing the callback + aesCBC256EncryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.ENCRYPT_MODE); + aesCBC256DecryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.DECRYPT_MODE); + aesCTR256EncryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.ENCRYPT_MODE); + aesCTR256DecryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.DECRYPT_MODE); + + hmacSha512Callback = new MacCallback("HmacSHA512"); + hmacSha256Callback = new MacCallback("HmacSHA256"); + sha256Callback = new MessageDigestCallback("SHA-256"); + secureRandomCallback = new SecureRandomCallback(new SecureRandom()); + + configure(() -> mongocrypt_setopt_crypto_hooks(wrapped, aesCBC256EncryptCallback, aesCBC256DecryptCallback, + secureRandomCallback, hmacSha512Callback, hmacSha256Callback, + sha256Callback, null)); + + signingRSAESPKCSCallback = new SigningRSAESPKCSCallback(); + configure(() -> mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(wrapped, signingRSAESPKCSCallback, null)); + configure(() -> mongocrypt_setopt_aes_256_ctr(wrapped, aesCTR256EncryptCallback, aesCTR256DecryptCallback, null)); + } if (options.getLocalKmsProviderOptions() != null) { try (BinaryHolder localMasterKeyBinaryHolder = toBinary(options.getLocalKmsProviderOptions().getLocalMasterKey())) {