Support OpenSSL backend and implement message digest - #1492
Support OpenSSL backend and implement message digest#1492KostasTsiounis wants to merge 3 commits into
Conversation
ff3a354 to
26a5ca2
Compare
|
I know we talked about contexts and one for FIPS and one for non-FIPS. Could we use the Property query instead? Does using this have any performance ramifications? |
04bc9c2 to
d4a4c94
Compare
1b76bd7 to
31add61
Compare
8920c23 to
0e09aab
Compare
c43bb68 to
117b14c
Compare
| #include "Utils.h" | ||
| #include <string.h> | ||
|
|
||
| int debug = 0; // FIXME |
There was a problem hiding this comment.
All gslogMessage calls always print to stderr regardless of the flag value
There was a problem hiding this comment.
This is following the same pattern that all OCK native code has. Do you think we should change this to have different levels of logging? We could open an issue to do this everywhere if we want.
dea939a to
1bb6a35
Compare
1bb6a35 to
555ccec
Compare
| * Signature: (JJI)V | ||
| */ | ||
| JNIEXPORT void JNICALL | ||
| Java_com_ibm_crypto_plus_provider_openssl_NativeOpenSSLImplementation_DIGEST_1digest_1and_1reset__JJI( |
There was a problem hiding this comment.
According to the parameters, this should be _JJJI
There was a problem hiding this comment.
Updated comment and method signature.
| static private ConcurrentLinkedQueueLong contexts[]; | ||
|
|
||
| static private int runtimeContextNum[]; | ||
| private static final Map<NativeInterface, Integer[]> runtimeContextNumPerBackend = new HashMap<>(); |
There was a problem hiding this comment.
I have a concern here by using two hashmaps. If I understand correctly, the backend cache state is published through two separate maps. Another thread can observe contextsPerBackend initialized before the corresponding runtimeContextNumPerBackend entry is published, skip initialization, and later dereference a null runtimeContextNum.
There was a problem hiding this comment.
I'm not sure I follow the train of thought here. Are you talking about the static class variables? These will be assigned to a new hashmap during the class initialization. When a thread actually attempts to get a context, it will go through the double check and synchronization lock in lines 75-78. The context queue per backend is also a concurrent one.
Did you mean something else that I missed here?
There was a problem hiding this comment.
Yes, I’m referring to the static per-backend maps, but the issue is not the initialization of the maps themselves or the ConcurrentLinkedQueue.
Consider two threads entering getContext() for a backend that has not been initialized yet. Both threads can initially read contexts == null and runtimeContextNum == null. Thread A acquires the lock first, initializes both entries, and releases the lock. Thread B then acquires the lock and re-reads only contextsPerBackend. Since contexts is now non-null, it skips the initialization block. However, Thread B never re-reads runtimeContextNumPerBackend, so its local runtimeContextNum variable is still null from the read before acquiring the lock.
There was a problem hiding this comment.
Maybe ConcurrentHashMap instead of Map ?
There was a problem hiding this comment.
I make sure to set runtimeContextNum in the synchronized block if contexts has already been set.
There was a problem hiding this comment.
I still have one concern here. Consider a backend that has not been initialized yet, then there are two threads.
Thread A enters the synchronized block and creates both contexts and runtimeContextNum. Then, thread A executes:
contextsPerBackend.put(this.nativeInterface, contexts);
but has not yet executed:
runtimeContextNumPerBackend.put(this.nativeInterface, runtimeContextNum);
At this point, thread B enters getContext() and performs the initial reads outside the synchronized block:
contexts = contextsPerBackend.get(this.nativeInterface);
runtimeContextNum = runtimeContextNumPerBackend.get(this.nativeInterface);
Thread B can observe:
contexts != null
runtimeContextNum == null
Since contexts != null, Thread B skips the synchronized block entirely, so the new re-read of runtimeContextNumPerBackend inside the lock is never reached.
I think either the two backend states need to be published atomically as one object, or both the get and put need to use the same synchronization.
There was a problem hiding this comment.
I updated to check both variables and wait for the synchronized block if either of them is not set. That way I think we can guarantee that no thread will move on without having values for both. See d3e59ad.
| goto cleanup; | ||
| } | ||
|
|
||
| rc = EVP_DigestFinal_ex(mdCtx, digestBytesNative, (unsigned int *)&digestLen); |
There was a problem hiding this comment.
Is there any reason why we call EVP_DigestFinal_ex twice? If you want to get the output buffer size, i believe you can do something like
int digestLen = EVP_MD_CTX_get_size(mdCtx);
digestBytes = (*env)->NewByteArray(env, digestLen);
unsigned int actualLen = 0;
EVP_DigestFinal_ex(
mdCtx,
digestBytesNative,
&actualLen);
There was a problem hiding this comment.
Changed to suggested API. It looks like EVP_DigestFinal_ex doesn't guarantee proper size.
| static private ConcurrentLinkedQueueLong contexts[]; | ||
|
|
||
| static private int runtimeContextNum[]; | ||
| private static final Map<NativeInterface, Integer[]> runtimeContextNumPerBackend = new HashMap<>(); |
There was a problem hiding this comment.
Maybe ConcurrentHashMap instead of Map ?
| public static NativeOpenSSLAdapterNonFIPS getInstance() { | ||
| if (instance == null) { | ||
| instance = new NativeOpenSSLAdapterNonFIPS(); | ||
| } |
There was a problem hiding this comment.
Is it guaranteed that NativeOpenSSLAdapterNonFIPS.getInstance() returns a single instance under concurrent first access? getInstance() itself is not synchronized and its instance field is not volatile, so two threads may construct different adapter instances.
This seems particularly relevant now that Digest uses the NativeInterface instance itself as the key for contextsPerBackend. Two adapter instances representing the same OpenSSL backend would therefore create separate digest caches.
There was a problem hiding this comment.
You are right. Changed to do a double check with synchronization in between.
521f2a4 to
9db9a0b
Compare
fdd6070 to
f01a83d
Compare
With this change, all appropriate code is added to support the use of OpenSSL as a backend. That includes: - Main Java class to load the libraries required and offer native methods. - Adapter Java classes to smoothly integrate without changes with existing code. - Makefiles to compile and link required C code to use OpenSSL. - Additional test tags and general test setup to allow the execution of appropriate tests with the new backend. Additionally, the first set of algorithms, namely the message digests, are implemented. The aforementioned tags are, also, added to the corresponding tests. Signed-off-by: Kostas Tsiounis <kostas.tsiounis@ibm.com>
f01a83d to
83363fd
Compare
|
I added some additional guards for |
| } | ||
|
|
||
| private String getExpectedLibraryVersion() { | ||
| return "3.0.0"; |

With this change, all appropriate code is added to support the use of
OpenSSLas a backend. That includes:OpenSSL.Additionally, the first set of algorithms, namely the message digests, are implemented. The aforementioned tags are, also, added to the corresponding tests.
Signed-off-by: Kostas Tsiounis kostas.tsiounis@ibm.com