Skip to content

Commit

Permalink
Merge pull request #224 from alexw91/aws-lc_rpath-dynamic-loading
Browse files Browse the repository at this point in the history
Dynamically load ACCP with AWS-LC using RPath
  • Loading branch information
alexw91 authored Jun 29, 2022
2 parents 76e7e1f + 0af7871 commit d6ac4ab
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 208 deletions.
30 changes: 15 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ string(REPLACE ":" ";" TEST_CLASSPATH_LIST "${TEST_CLASSPATH}")

# Needed as we abuse some of the test compile macros to test shared lib links
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# CMake's default RPath handling includes the full build directory path, which isn't needed. Turn it off.
set(CMAKE_SKIP_RPATH TRUE)
set(GENERATE_HASHERS ${CMAKE_CURRENT_SOURCE_DIR}/build-tools/bin/generate-java-hash-spi)
set(GENERATED_JAVA_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated-java/com/amazon/corretto/crypto/provider)
set(JNI_HEADER_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated-include)
Expand Down Expand Up @@ -231,9 +232,9 @@ else()
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_SOURCE_DIR}/extra-jar-files .
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C $<TARGET_PROPERTY:module-jar,CLASSDIR> module-info.class
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} $<TARGET_FILE_DIR:amazonCorrettoCryptoProvider>
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:amazonCorrettoCryptoProvider> ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:accpLcLoader> ${CMAKE_CURRENT_BINARY_DIR}/tmplib/com/amazon/corretto/crypto/provider/
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_BINARY_DIR}/tmplib/ com/amazon/corretto/crypto/provider/
COMMAND ${Java_JAR_EXECUTABLE} uf ${ACCP_JAR_TMP} -C ${CMAKE_CURRENT_BINARY_DIR}/generated-java/ com/amazon/corretto/crypto/provider/version.properties
COMMAND ${CMAKE_COMMAND} -E copy ${ACCP_JAR_TMP} ${ACCP_JAR}
Expand Down Expand Up @@ -266,12 +267,6 @@ ADD_CUSTOM_COMMAND(
### Native library configuration
include_directories(${OPENSSL_INCLUDE_DIR} ${JNI_INCLUDE_DIRS} ${JNI_HEADER_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp)

add_library(
accpLcLoader SHARED
csrc/accp_lc_loader.cpp
${JNI_HEADER_DIR}/generated-headers.h
)

add_library(
amazonCorrettoCryptoProvider SHARED
csrc/aes_gcm.cpp
Expand Down Expand Up @@ -300,6 +295,11 @@ add_library(
${JNI_HEADER_DIR}/generated-headers.h
)

# We MUST set ACCP's RPATH to "$ORIGIN" so that the runtime dynamic loader will look in the same directory as ACCP for
# any shared library dependencies BEFORE looking for a system-installed depencencies (such as libcrypto). If RPath is
# not set, the loader may attempt to load an incompatible system-installed libcrypto and cause runtime crashes.
set_target_properties(amazonCorrettoCryptoProvider PROPERTIES LINK_FLAGS "-Wl,-rpath,\$ORIGIN")

add_custom_command(
OUTPUT ${ACCP_JAR_SOURCE}
COMMAND ${Java_JAR_EXECUTABLE} cf ${ACCP_JAR_SOURCE} -C ${CMAKE_CURRENT_SOURCE_DIR}/src .
Expand All @@ -315,6 +315,7 @@ if(ENABLE_NATIVE_TEST_HOOKS)
add_executable(test_keyutils EXCLUDE_FROM_ALL
csrc/test_keyutils.cpp
)
set_target_properties(test_keyutils PROPERTIES LINK_FLAGS "-Wl,-rpath,\$ORIGIN")
target_link_libraries(test_keyutils ${OPENSSL_CRYPTO_LIBRARY})
target_link_libraries(test_keyutils amazonCorrettoCryptoProvider)
endif()
Expand Down Expand Up @@ -373,7 +374,6 @@ CHECK_LIBRARY_EXISTS(m "sqrt" "" HAVE_LIBM)

if(HAVE_LIBDL)
target_link_libraries(amazonCorrettoCryptoProvider dl)
target_link_libraries(accpLcLoader dl)
endif()

if(HAVE_LIBM)
Expand Down Expand Up @@ -460,9 +460,6 @@ int main(int, char **) noexcept {}
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${OLD_CMAKE_EXE_LINKER_FLAGS}")

# We do not declare an explicit on libcrypto to ensure we're using our bundled version.
# If this ends up being a problem on some platforms we can figure out a different way to manage this.

# Miscellaneous linker flag tests. Unfortunately cmake doesn't have built-in
# functionality for a linker flag test, so we have to roll our own.

Expand Down Expand Up @@ -545,11 +542,13 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROVIDER_VERSION_STRING=${PROVIDER_VER
string(STRIP "${PROBED_LINKED_FLAGS}" PROBED_LINKED_FLAGS)
MESSAGE(STATUS "probed flags ${PROBED_LINKED_FLAGS}")
target_link_libraries(amazonCorrettoCryptoProvider ${PROBED_LINKED_FLAGS})
target_link_libraries(accpLcLoader ${PROBED_LINKED_FLAGS})

# Add pthread support
target_link_libraries(amazonCorrettoCryptoProvider Threads::Threads)

# Take a dependency on our libcrypto.so file
target_link_libraries(amazonCorrettoCryptoProvider ${OPENSSL_CRYPTO_LIBRARY})

## Tests
add_jar(
tests-code-jar
Expand Down Expand Up @@ -642,7 +641,7 @@ else()
endif()

if(ALWAYS_ALLOW_EXTERNAL_LIB)
set(EXTERNAL_LIB_PROPERTY "-Djava.library.path=$<TARGET_FILE_DIR:amazonCorrettoCryptoProvider>:$<TARGET_FILE_DIR:accpLcLoader>")
set(EXTERNAL_LIB_PROPERTY "-Djava.library.path=$<TARGET_FILE_DIR:amazonCorrettoCryptoProvider>")
endif()

set(TEST_RUNNER_ARGUMENTS
Expand Down Expand Up @@ -749,7 +748,7 @@ add_custom_target(check-external-lib
${TEST_FIPS_PROPERTY}
-cp $<TARGET_PROPERTY:accp-jar,JAR_FILE>:$<TARGET_PROPERTY:tests-jar,JAR_FILE>:${TEST_CLASSPATH}
# Since this tests external loading we always provide this property
-Djava.library.path=$<TARGET_FILE_DIR:amazonCorrettoCryptoProvider>:$<TARGET_FILE_DIR:accpLcLoader>
-Djava.library.path=$<TARGET_FILE_DIR:amazonCorrettoCryptoProvider>
-Dcom.amazon.corretto.crypto.provider.useExternalLib=true
-Dcom.amazon.corretto.crypto.provider.inTestSuite=hunter2
-Dtest.data.dir=${TEST_DATA_DIR}
Expand Down Expand Up @@ -802,6 +801,7 @@ add_custom_target(checkstyle

if(ENABLE_NATIVE_TEST_HOOKS)
add_custom_target(check-keyutils
COMMAND ${CMAKE_COMMAND} -E copy ${OPENSSL_CRYPTO_LIBRARY} $<TARGET_FILE_DIR:test_keyutils>
COMMAND $<TARGET_FILE:test_keyutils>
)
add_dependencies(check check-keyutils)
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ task buildAwsLc {
args '-DBUILD_SHARED_LIBS=ON'
args '-DCMAKE_BUILD_TYPE=RelWithDebInfo'
args "-DCMAKE_INSTALL_PREFIX=${sharedObjectOutDir}"
args "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"

if (isFips) {
args '-DFIPS=1'
Expand Down Expand Up @@ -123,6 +124,7 @@ task executeCmake(type: Exec) {
args "-DOPENSSL_ROOT_DIR=${buildDir}/awslc/bin", '-DCMAKE_BUILD_TYPE=Release', '-DPROVIDER_VERSION_STRING=' + version
args "-DTEST_RUNNER_JAR=${configurations.testRunner.singleFile}"
args "-DCHECKSTYLE_CP=${configurations.checkstyle.asPath}"
args "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
if (isFips) {
args "-DFIPS=ON"
}
Expand Down Expand Up @@ -301,6 +303,7 @@ task coverage_cmake(type: Exec) {
args '-DCMAKE_BUILD_TYPE=Coverage', '-DCOVERAGE=ON', '-DENABLE_NATIVE_TEST_HOOKS=ON'
args '-DPROVIDER_VERSION_STRING=' + version, projectDir
args "-DTEST_RUNNER_JAR=${configurations.testRunner.singleFile}"
args "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
if (isFips) {
args "-DFIPS=ON"
}
Expand Down
76 changes: 0 additions & 76 deletions csrc/accp_lc_loader.cpp

This file was deleted.

7 changes: 2 additions & 5 deletions csrc/env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,8 @@ void java_ex::throw_to_java(JNIEnv *env) {

if (likely(ex_class != NULL)) {
std::ostringstream oss;
if (m_message_cstr) {
oss << m_message_cstr;
} else {
oss << m_message;
}
oss << m_message;

#ifdef BACKTRACE_ON_EXCEPTION
format_trace(oss, m_trace);
#endif
Expand Down
12 changes: 6 additions & 6 deletions csrc/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class java_ex {

const char *m_java_classname;
const std::string m_message;
const char *m_message_cstr;
#ifdef BACKTRACE_ON_EXCEPTION
std::vector<void *> m_trace;
void capture_trace() COLD { AmazonCorrettoCryptoProvider::capture_trace(m_trace); }
Expand All @@ -61,16 +60,17 @@ class java_ex {

public:
java_ex(jthrowable exception) COLD
: m_java_exception(exception), m_java_classname(nullptr), m_message(), m_message_cstr("")
: m_java_exception(exception), m_java_classname(nullptr), m_message()
{ }

java_ex(const char *java_classname, const char *message) COLD
: m_java_exception(nullptr), m_java_classname(java_classname), m_message(), m_message_cstr(message)
{ capture_trace(); }
: java_ex(java_classname, std::string(message)) {
}

java_ex(const char *java_classname, const std::string &message) COLD
: m_java_exception(nullptr), m_java_classname(java_classname), m_message(message), m_message_cstr(nullptr)
{ capture_trace(); }
: m_java_exception(nullptr), m_java_classname(java_classname), m_message(message) {
capture_trace();
}

/**
* Constructs an exception based on the openssl error code.
Expand Down
32 changes: 32 additions & 0 deletions csrc/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
// Right now we only support PTHREAD
#include <pthread.h>

// https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_VERSION_NUMBER.html
// 0xMNNFFPPS : major minor fix patch status
// 0x1010107f == v1.1.1g release
#define LIBCRYPTO_MAJOR_MINOR_VERSION_MASK 0xFFF00000

using namespace AmazonCorrettoCryptoProvider;

Expand Down Expand Up @@ -60,3 +64,31 @@ JNIEXPORT jstring JNICALL Java_com_amazon_corretto_crypto_provider_Loader_getNat
}

}

JNIEXPORT jboolean JNICALL Java_com_amazon_corretto_crypto_provider_Loader_validateLibcryptoVersion(JNIEnv* pEnv, jclass, jboolean jFuzzyMatch)
{
bool fuzzyMatch = (jFuzzyMatch == JNI_TRUE);

try {
unsigned long libcrypto_compiletime_version = OPENSSL_VERSION_NUMBER;
unsigned long libcrypto_runtime_version = OpenSSL_version_num();

if (fuzzyMatch) {
libcrypto_compiletime_version &= LIBCRYPTO_MAJOR_MINOR_VERSION_MASK;
libcrypto_runtime_version &= LIBCRYPTO_MAJOR_MINOR_VERSION_MASK;
}

if (libcrypto_compiletime_version != libcrypto_runtime_version) {
char accp_loader_exception_msg[256] = {0};
snprintf(accp_loader_exception_msg, sizeof(accp_loader_exception_msg),
"Runtime libcrypto version does not match compile-time version. Expected: 0x%08lX , Actual: 0x%08lX",
libcrypto_compiletime_version, libcrypto_runtime_version);
throw java_ex(EX_RUNTIME_CRYPTO, accp_loader_exception_msg);
}
return JNI_TRUE;
} catch (java_ex &ex) {
ex.throw_to_java(pEnv);
}

return JNI_FALSE;
}
1 change: 1 addition & 0 deletions src/com/amazon/corretto/crypto/provider/AesGcmSpi.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ private static native int encryptDoFinal(
private final AccessibleByteArrayOutputStream decryptAADBuf = new AccessibleByteArrayOutputStream();

AesGcmSpi(final AmazonCorrettoCryptoProvider provider) {
Loader.checkNativeLibraryAvailability();
this.provider = provider;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,15 +266,16 @@ public AmazonCorrettoCryptoProvider() {

Utils.optionsFromProperty(ExtraCheck.class, extraChecks, "extrachecks");

if (!Loader.IS_AVAILABLE && DebugFlag.VERBOSELOGS.isEnabled()) {
getLogger("AmazonCorrettoCryptoProvider").fine("Native JCE libraries are unavailable - disabling");
if (!Loader.IS_AVAILABLE) {
if (DebugFlag.VERBOSELOGS.isEnabled()) {
getLogger("AmazonCorrettoCryptoProvider").fine("Native JCE libraries are unavailable - disabling");
}

// Don't implement anything
// If Loading failed, do not register any algorithms
return;
}

buildServiceMap();

initializeSelfTests();
}

Expand Down
1 change: 1 addition & 0 deletions src/com/amazon/corretto/crypto/provider/EcGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ protected NativeParams initialValue() {
private ECInfo ecInfo = null;

EcGen(AmazonCorrettoCryptoProvider provider) {
Loader.checkNativeLibraryAvailability();
provider_ = provider;
}

Expand Down
1 change: 1 addition & 0 deletions src/com/amazon/corretto/crypto/provider/EvpKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ abstract class EvpKey implements Key, Destroyable {
protected static native byte[] getDerEncodedParams(long ptr);

EvpKey(final InternalKey key, final EvpKeyType type, final boolean isPublicKey) {
Loader.checkNativeLibraryAvailability();
this.internalKey = key;
this.type = type;
this.isPublicKey = isPublicKey;
Expand Down
1 change: 1 addition & 0 deletions src/com/amazon/corretto/crypto/provider/EvpKeyFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ abstract class EvpKeyFactory extends KeyFactorySpi {
private static native long ec2Evp(byte[] s, byte[] wx, byte[] wy, byte[] params, boolean checkPrivate) throws InvalidKeySpecException;

protected EvpKeyFactory(EvpKeyType type, AmazonCorrettoCryptoProvider provider) {
Loader.checkNativeLibraryAvailability();
this.type = type;
this.provider = provider;
if (this.type == null) {
Expand Down
1 change: 1 addition & 0 deletions src/com/amazon/corretto/crypto/provider/LibCryptoRng.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class LibCryptoRng extends SecureRandom {

public LibCryptoRng() {
super(new SPI(), AmazonCorrettoCryptoProvider.INSTANCE);
Loader.checkNativeLibraryAvailability();
}

@Override
Expand Down
Loading

0 comments on commit d6ac4ab

Please sign in to comment.