Skip to content

Commit

Permalink
Ktls reviews (#6)
Browse files Browse the repository at this point in the history
Addressed review comments in OSR-105 and added license

JIRA Ticket: LIKAFKA-52908
  • Loading branch information
vp224 authored Jul 29, 2023
1 parent 01b628e commit 97e30da
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 21 deletions.
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ publishing {
publications {
maven(MavenPublication) {
from components.java
pom {
url = 'https://github.com/linkedin/ktls-jni'
licenses {
license {
name = 'BSD 2-Clause License'
url = 'https://opensource.org/licenses/BSD-2-Clause'
distribution = 'repo'
}
}
}
}
}
}
Expand Down
39 changes: 26 additions & 13 deletions src/main/cpp/KernelTLSNativeHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,20 @@ int enableTlsWithCryptoInfo(int socketFd, bool sendingMode, void* crypto_info, u
return 0;
}

void copyArray(JNIEnv *env, jbyteArray &src, unsigned char *dest) {
int copyArray(JNIEnv *env, jbyteArray &src, unsigned char *dest, size_t destSize) {
jbyte* srcArr = env->GetByteArrayElements(src, NULL);
jsize len = env->GetArrayLength(src);

if (len > destSize) {
env->ReleaseByteArrayElements(src, srcArr, JNI_ABORT);
return -1;
}

for (int idx = 0; idx < len; idx++) {
dest[idx] = (unsigned char) srcArr[idx];
}
env->ReleaseByteArrayElements(src, srcArr, JNI_ABORT);
return len;
}
#endif

Expand All @@ -59,10 +66,12 @@ JNIEXPORT jint JNICALL Java_com_linkedin_ktls_KernelTLSNativeHelper_enableKernel
struct tls12_crypto_info_aes_gcm_128 crypto_info;
crypto_info.info.version = versionCode;
crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128;
copyArray(env, iv, crypto_info.iv);
copyArray(env, key, crypto_info.key);
copyArray(env, salt, crypto_info.salt);
copyArray(env, rec_seq, crypto_info.rec_seq);
int result_iv = copyArray(env, iv, crypto_info.iv, sizeof(crypto_info.iv));
int result_key = copyArray(env, key, crypto_info.key, sizeof(crypto_info.key));
int result_salt = copyArray(env, salt, crypto_info.salt, sizeof(crypto_info.salt));
int result_rec_seq = copyArray(env, rec_seq, crypto_info.rec_seq, sizeof(crypto_info.rec_seq));
if(result_iv == -1 || result_key == -1 || result_salt == -1 || result_rec_seq == -1)
return com_linkedin_ktls_KernelTLSNativeHelper_BUFFER_OVERRUN;
return enableTlsWithCryptoInfo(socketFd, true, &crypto_info, sizeof(crypto_info));
#endif
}
Expand All @@ -76,10 +85,12 @@ JNIEXPORT jint JNICALL Java_com_linkedin_ktls_KernelTLSNativeHelper_enableKernel
struct tls12_crypto_info_aes_gcm_256 crypto_info;
crypto_info.info.version = versionCode;
crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_256;
copyArray(env, iv, crypto_info.iv);
copyArray(env, key, crypto_info.key);
copyArray(env, salt, crypto_info.salt);
copyArray(env, rec_seq, crypto_info.rec_seq);
int result_iv = copyArray(env, iv, crypto_info.iv, sizeof(crypto_info.iv));
int result_key = copyArray(env, key, crypto_info.key, sizeof(crypto_info.key));
int result_salt = copyArray(env, salt, crypto_info.salt, sizeof(crypto_info.salt));
int result_rec_seq = copyArray(env, rec_seq, crypto_info.rec_seq, sizeof(crypto_info.rec_seq));
if(result_iv == -1 || result_key == -1 || result_salt == -1 || result_rec_seq == -1)
return com_linkedin_ktls_KernelTLSNativeHelper_BUFFER_OVERRUN;
return enableTlsWithCryptoInfo(socketFd, true, &crypto_info, sizeof(crypto_info));
#endif
}
Expand All @@ -93,10 +104,12 @@ JNIEXPORT jint JNICALL Java_com_linkedin_ktls_KernelTLSNativeHelper_enableKernel
struct tls12_crypto_info_chacha20_poly1305 crypto_info;
crypto_info.info.version = versionCode;
crypto_info.info.cipher_type = TLS_CIPHER_CHACHA20_POLY1305;
copyArray(env, iv, crypto_info.iv);
copyArray(env, key, crypto_info.key);
copyArray(env, salt, crypto_info.salt);
copyArray(env, rec_seq, crypto_info.rec_seq);
int result_iv = copyArray(env, iv, crypto_info.iv, sizeof(crypto_info.iv));
int result_key = copyArray(env, key, crypto_info.key, sizeof(crypto_info.key));
int result_salt = copyArray(env, salt, crypto_info.salt, sizeof(crypto_info.salt));
int result_rec_seq = copyArray(env, rec_seq, crypto_info.rec_seq, sizeof(crypto_info.rec_seq));
if(result_iv == -1 || result_key == -1 || result_salt == -1 || result_rec_seq == -1)
return com_linkedin_ktls_KernelTLSNativeHelper_BUFFER_OVERRUN;
return enableTlsWithCryptoInfo(socketFd, true, &crypto_info, sizeof(crypto_info));
#endif
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 55 additions & 8 deletions src/main/java/com/linkedin/ktls/KernelTLSNativeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class KernelTLSNativeHelper {
private static final int UNSUPPORTED_OPERATION = 6003;
private static final int UNABLE_TO_SET_TLS_MODE = 6004;
private static final int UNABLE_TO_SET_TLS_PARAMS = 6005;
private static final int BUFFER_OVERRUN = 6006;

private static final byte RECORD_TYPE_ALERT = 21;
private static final byte ALERT_LEVEL_WARNING = 1;
Expand All @@ -26,16 +27,33 @@ class KernelTLSNativeHelper {
Native.load();
}

/**
* Extracts the file descriptor associated with the given SocketChannel.
*
* @param socketChannel The SocketChannel from which to extract the file descriptor.
* @return The integer file descriptor associated with the SocketChannel.
* @throws IllegalArgumentException If there is an error while extracting the file descriptor.
*/
int extractFd(SocketChannel socketChannel) {
try {
// Retrieve the 'fd' field from the 'sun.nio.ch.SocketChannelImpl' class using ReflectionUtils.
final Object fileDescriptor =
ReflectionUtils.getValueAtField("sun.nio.ch.SocketChannelImpl", "fd", socketChannel);
// Convert the result to an integer and return it as the file descriptor.
return (int) ReflectionUtils.getValueAtField("java.io.FileDescriptor", "fd", fileDescriptor);
} catch (Exception e) {
// If there is any exception while extracting the file descriptor, wrap it in an IllegalArgumentException
// and rethrow it to signal an error.
throw new IllegalArgumentException(e);
}
}

/**
* This function tries to enable kernelTLS for send based on the symmetric cipher value.
* @param socketChannel SocketChannel object to enable kernelTLS on
* @param tlsParameters TlsParameters with the symmetric cipher based on which we decide if kernel TLS can be enabled.
* @throws KTLSEnableFailedException
*/
void enableKernelTlsForSend(SocketChannel socketChannel, TlsParameters tlsParameters)
throws KTLSEnableFailedException {
final int fd;
Expand All @@ -62,27 +80,47 @@ void enableKernelTlsForSend(SocketChannel socketChannel, TlsParameters tlsParame
throw new IllegalStateException();
}
if (retCode != 0) {
throw buildExceptionForReturnCode(retCode);
throw buildExceptionForReturnCode(retCode, tlsParameters.symmetricCipher);
}
}

private KTLSEnableFailedException buildExceptionForReturnCode(int retCode) {
/**
* This function is to throw the respective exception based on the return value from the underlying JNI kernel TLS enable call.
* Also used OS version and symmetric cipher version for logging the exceptions.
* @param retCode Return value after performing kernel TLS enabled send
* @param symmetricCipher Symmetric cipher used for logging in the exceptions.
* @return
*/
private KTLSEnableFailedException buildExceptionForReturnCode(int retCode, SymmetricCipher symmetricCipher) {
String osVersion = System.getProperty("os.version");
switch (retCode) {
case UNSUPPORTED_OPERATING_SYSTEM:
return new KTLSEnableFailedException("ktls-jni was not built with support for this operating system");
return new KTLSEnableFailedException(
"ktls-jni was not built with support for this operating system. os version: " + osVersion
+ ", symmetricCipher: " + symmetricCipher);
case UNSUPPORTED_CIPHER:
return new KTLSEnableFailedException("ktls-jni was not built with support for the specified cipher");
return new KTLSEnableFailedException(
"ktls-jni was not built with support for the specified cipher. os version: " + osVersion
+ ", symmetricCipher: " + symmetricCipher);
case UNSUPPORTED_OPERATION:
return new KTLSEnableFailedException("This action is not supported.");
return new KTLSEnableFailedException(
"This action is not supported. os version: " + osVersion + ", symmetricCipher: " + symmetricCipher);
case UNABLE_TO_SET_TLS_MODE:
return new KTLSEnableFailedException("Unable to set socket to TLS mode. "
+ "This may indicate that the \"tls\" kernel module is not enabled.");
+ "This may indicate that the \"tls\" kernel module is not enabled on os version: " + osVersion
+ ", symmetricCipher: " + symmetricCipher);
case UNABLE_TO_SET_TLS_PARAMS:
return new KTLSEnableFailedException("Unable to set TLS parameters on socket. "
+ "This is an unexpected scenario and needs further investigation.");
+ "This is an unexpected scenario and needs further investigation. os version: " + osVersion
+ ", symmetricCipher: " + symmetricCipher);
case BUFFER_OVERRUN:
return new KTLSEnableFailedException(
"Found buffer overrun during copy array call. os version: " + osVersion + ", symmetricCipher: "
+ symmetricCipher);
default:
return new KTLSEnableFailedException(String.format(
"Unexpected error when trying to initialize Kernel TLS, return code %s", retCode));
"Unexpected error when trying to initialize Kernel TLS, return code %s. os version : %s , symmetricCipher: %s",
retCode, osVersion, symmetricCipher));
}
}

Expand All @@ -93,6 +131,10 @@ private native int enableKernelTlsForSend_AES_256_GCM(
private native int enableKernelTlsForSend_CHACHA20_POLY1305(
int fd, int version_code, byte[] iv, byte[] key, byte[] salt, byte[] rec_seq);

/**
* This method is used to populate the supported symmetric ciphers using an ciphers array returned from NativeHelper.cpp.
* @return List<String> containing the cipher suites list.
*/
public List<String> getSupportedCipherSuites() {
final Set<String> supportedSymmetricCiphers = new HashSet<>(Arrays.asList(getSupportedSymmetricCiphers()));
return Arrays.stream(CipherSuite.values())
Expand All @@ -103,6 +145,11 @@ public List<String> getSupportedCipherSuites() {

private native String[] getSupportedSymmetricCiphers();

/**
* This method is used to extract the file descriptor and send a close alert to the file descriptor.
* @param socketChannel SocketChannel object that is to be closed
* @throws IOException
*/
public void sendCloseNotify(SocketChannel socketChannel) throws IOException {
final int socketFd = extractFd(socketChannel);
final byte[] data = new byte[2];
Expand Down

0 comments on commit 97e30da

Please sign in to comment.