Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
6 changes: 6 additions & 0 deletions android/lint.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@
<issue id="Assert">
<ignore path="**/common/src/main/java/org/conscrypt/OpenSSLCipherChaCha20.java" />
</issue>

<!-- Workaround for "Unexpected failure during lint analysis". -->
<issue id="LintError">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

side note: do you know why this is necessary for your setup? I don't see any issues locally, but it might be due to some version difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had forgotten about this change. I assume it's an issue with my local configuration but the error wasn't specific. I can pull it out when I'm done.

<ignore regexp=".*module-info\.class.*"/>
</issue>

</lint>
227 changes: 225 additions & 2 deletions common/src/jni/main/cpp/conscrypt/native_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ static SSL_CIPHER* to_SSL_CIPHER(JNIEnv* env, jlong ssl_cipher_address, bool thr
return ssl_cipher;
}

static SSL_ECH_KEYS* to_SSL_ECH_KEYS(JNIEnv* env, jlong ssl_ech_keys_address, bool throwIfNull) {
SSL_ECH_KEYS* ssl_ech_keys =
reinterpret_cast<SSL_ECH_KEYS*>(static_cast<uintptr_t>(ssl_ech_keys_address));
if ((ssl_ech_keys == nullptr) && throwIfNull) {
JNI_TRACE("ssl_ech_keys == null");
conscrypt::jniutil::throwNullPointerException(env, "ssl_ech_keys == null");
}
return ssl_ech_keys;
}

template <typename T>
static T* fromContextObject(JNIEnv* env, jobject contextObject) {
if (contextObject == nullptr) {
Expand Down Expand Up @@ -7825,7 +7835,12 @@ static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData,
if (fds[1].revents & POLLIN) {
char token;
do {
(void)read(appData->fdsEmergency[0], &token, 1);
// TEMP - fixes build error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you get a compiler warning here otherwise?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was more specific:

error: ignoring return value of ‘ssize_t read(int, void*, size_t)’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
 7798 |                 (void)read(appData->fdsEmergency[0], &token, 1);
      |                       ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First I tried assigning the result to a variable, but then it complained that the variable was unused and that's how I ended up with the current fix. There's about 4 places where this happens but this was the only one in a file I had to commit.

int foo = 0;
foo = read(appData->fdsEmergency[0], &token, 1);
if (foo > 0) {
CONSCRYPT_LOG_VERBOSE("FOO: %d", foo);
}
} while (errno == EINTR);
}
}
Expand Down Expand Up @@ -7856,7 +7871,12 @@ static void sslNotify(AppData* appData) {
char token = '*';
do {
errno = 0;
(void)write(appData->fdsEmergency[1], &token, 1);
// TEMP - fixes build error
int foo = 0;
foo = write(appData->fdsEmergency[1], &token, 1);
if (foo > 0) {
CONSCRYPT_LOG_VERBOSE("FOO: %d", foo);
}
} while (errno == EINTR);
errno = errnoBackup;
#endif
Expand Down Expand Up @@ -11815,6 +11835,198 @@ static jlong NativeCrypto_SSL_get1_session(JNIEnv* env, jclass, jlong ssl_addres
return reinterpret_cast<uintptr_t>(SSL_get1_session(ssl));
}

static void NativeCrypto_SSL_set_enable_ech_grease(JNIEnv* env, jclass, jlong ssl_address,
CONSCRYPT_UNUSED jobject ssl_holder,
jboolean enable) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_set_enable_ech_grease(%d)", ssl, enable);
if (ssl == nullptr) {
return;
}
SSL_set_enable_ech_grease(ssl, enable ? 1 : 0);
JNI_TRACE("ssl=%p NativeCrypto_SSL_set_enable_ech_grease(%d) => success", ssl, enable);
}

static jboolean NativeCrypto_SSL_set1_ech_config_list(JNIEnv* env, jclass, jlong ssl_address,
CONSCRYPT_UNUSED jobject ssl_holder,
jbyteArray configJavaBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p)", ssl, configJavaBytes);
if (ssl == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Null pointer, ssl address");
ERR_clear_error();
return JNI_FALSE;
}
ScopedByteArrayRO configBytes(env, configJavaBytes);
if (configBytes.get() == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Null pointer, ech config");
ERR_clear_error();
JNI_TRACE("NativeCrypto_SSL_set1_ech_config_list => could not read config bytes");
return JNI_FALSE;
}
int ret = SSL_set1_ech_config_list(ssl, reinterpret_cast<const uint8_t*>(configBytes.get()),
configBytes.size());
if (!ret) {
conscrypt::jniutil::throwParsingException(env, "Error parsing ECH config");
ERR_clear_error();
JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p) => threw exception", ssl,
configJavaBytes);
return JNI_FALSE;
}

JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p) => %d", ssl, configJavaBytes, ret);
return ret;
}

static jstring NativeCrypto_SSL_get0_ech_name_override(JNIEnv* env, jclass, jlong ssl_address,
CONSCRYPT_UNUSED jobject ssl_holder) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_ech_name_override()", ssl);
if (ssl == nullptr) {
JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_ech_name_override() => nullptr", ssl);
return nullptr;
}
const char* ech_name_override;
size_t ech_name_override_len;
SSL_get0_ech_name_override(ssl, &ech_name_override, &ech_name_override_len);
if (ech_name_override_len > 0) {
jstring name = env->NewStringUTF(ech_name_override);
return name;
}
return nullptr;
}

static jbyteArray NativeCrypto_SSL_get0_ech_retry_configs(JNIEnv* env, jclass, jlong ssl_address,
CONSCRYPT_UNUSED jobject ssl_holder) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_ech_retry_configs()", ssl);
if (ssl == nullptr) {
return nullptr;
}
const uint8_t* retry_configs;
size_t retry_configs_len;
SSL_get0_ech_retry_configs(ssl, &retry_configs, &retry_configs_len);
if (retry_configs_len <= 0) {
return nullptr;
}
jbyteArray result = env->NewByteArray(static_cast<jsize>(retry_configs_len));
if (result == nullptr) {
JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_ech_retry_configs() => creating byte array failed",
ssl);
return nullptr;
}
env->SetByteArrayRegion(result, 0, static_cast<jsize>(retry_configs_len),
reinterpret_cast<const jbyte*>(retry_configs));
JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_ech_retry_configs() => %p", ssl, result);
return result;
}

static jlong NativeCrypto_SSL_ECH_KEYS_new(JNIEnv* env, jclass) {
CHECK_ERROR_QUEUE_ON_RETURN;
bssl::UniquePtr<SSL_ECH_KEYS> sslEchKeys(SSL_ECH_KEYS_new());
if (sslEchKeys.get() == nullptr) {
conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "SSL_ECH_KEYS_new");
return 0;
}
JNI_TRACE("NativeCrypto_SSL_ECH_KEYS_new => %p", sslEchKeys.get());
return (jlong)sslEchKeys.release();
}

static void NativeCrypto_SSL_ECH_KEYS_up_ref(JNIEnv* env, jclass, jlong ssl_ech_keys_address) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL_ECH_KEYS* ssl_ech_keys = to_SSL_ECH_KEYS(env, ssl_ech_keys_address, true);
JNI_TRACE("ssl_ech_keys=%p NativeCrypto_SSL_ECH_KEYS_up_ref", ssl_ech_keys);
if (ssl_ech_keys == nullptr) {
return;
}
SSL_ECH_KEYS_up_ref(ssl_ech_keys);
}

static void NativeCrypto_SSL_ECH_KEYS_free(JNIEnv* env, jclass, jlong ssl_ech_keys_address) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL_ECH_KEYS* ssl_ech_keys = to_SSL_ECH_KEYS(env, ssl_ech_keys_address, true);
JNI_TRACE("ssl_ech_keys=%p NativeCrypto_SSL_ECH_KEYS_free", ssl_ech_keys);
if (ssl_ech_keys == nullptr) {
return;
}
SSL_ECH_KEYS_free(ssl_ech_keys);
}

static jboolean NativeCrypto_SSL_ech_accepted(JNIEnv* env, jclass, jlong ssl_address,
CONSCRYPT_UNUSED jobject ssl_holder) {
JNI_TRACE("NativeCrypto_SSL_ech_accepted");
CHECK_ERROR_QUEUE_ON_RETURN;
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_ech_accepted", ssl);
if (ssl == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Null pointer, ssl address");
ERR_clear_error();
return JNI_FALSE;
}
jboolean accepted = SSL_ech_accepted(ssl);

if (!accepted) {
conscrypt::jniutil::throwParsingException(env, "Invalid ECH config list");
ERR_clear_error();
JNI_TRACE("ssl=%p NativeCrypto_SSL_ech_accepted => threw exception", ssl);
return JNI_FALSE;
}

JNI_TRACE("ssl=%p NativeCrypto_SSL_ech_accepted => %d", ssl, accepted);
return accepted;
}

static jboolean NativeCrypto_SSL_CTX_ech_enable_server(JNIEnv* env, jclass, jlong ssl_ctx_address,
CONSCRYPT_UNUSED jobject holder,
jbyteArray keyJavaBytes,
jbyteArray configJavaBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
JNI_TRACE("NativeCrypto_SSL_CTX_ech_enable_server(keyJavaBytes=%p, configJavaBytes=%p)",
keyJavaBytes, configJavaBytes);
ScopedByteArrayRO keyBytes(env, keyJavaBytes);
if (keyBytes.get() == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Null pointer, key bytes");
ERR_clear_error();
JNI_TRACE(
"NativeCrypto_SSL_CTX_ech_enable_server => threw exception: "
"could not read key bytes");
return JNI_FALSE;
}
ScopedByteArrayRO configBytes(env, configJavaBytes);
if (configBytes.get() == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Null pointer, config bytes");
ERR_clear_error();
JNI_TRACE(
"NativeCrypto_SSL_CTX_ech_enable_server => threw exception: "
"could not read config bytes");
return JNI_FALSE;
}
const uint8_t* ech_key = reinterpret_cast<const uint8_t*>(keyBytes.get());
size_t ech_key_size = keyBytes.size();
const uint8_t* ech_config = reinterpret_cast<const uint8_t*>(configBytes.get());
size_t ech_config_size = configBytes.size();
bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
bssl::ScopedEVP_HPKE_KEY key;
if (!keys ||
!EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(), ech_key, ech_key_size) ||
!SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config, ech_config_size,
key.get()) ||
!SSL_CTX_set1_ech_keys(ssl_ctx, keys.get())) {
conscrypt::jniutil::throwInvalidKeyException(env, "Key config error");
ERR_clear_error();
JNI_TRACE(
"NativeCrypto_SSL_CTX_ech_enable_server: "
"Error setting server's ECHConfig and private key\n");
return JNI_FALSE;
}
return JNI_TRUE;
}

// TESTING METHODS END

#define CONSCRYPT_NATIVE_METHOD(functionName, signature) \
Expand Down Expand Up @@ -12172,6 +12384,17 @@ static JNINativeMethod sNativeCryptoMethods[] = {
CONSCRYPT_NATIVE_METHOD(Scrypt_generate_key, "([B[BIIII)[B"),
CONSCRYPT_NATIVE_METHOD(SSL_CTX_set_spake_credential, "([B[B[B[BZIJ" REF_SSL_CTX ")V"),

// FOR ECH TESTING
CONSCRYPT_NATIVE_METHOD(SSL_set_enable_ech_grease, "(J" REF_SSL "Z)V"),
CONSCRYPT_NATIVE_METHOD(SSL_set1_ech_config_list, "(J" REF_SSL "[B)Z"),
CONSCRYPT_NATIVE_METHOD(SSL_get0_ech_name_override, "(J" REF_SSL ")Ljava/lang/String;"),
CONSCRYPT_NATIVE_METHOD(SSL_get0_ech_retry_configs, "(J" REF_SSL ")[B"),
CONSCRYPT_NATIVE_METHOD(SSL_ECH_KEYS_new, "()J"),
CONSCRYPT_NATIVE_METHOD(SSL_ECH_KEYS_up_ref, "(J)V"),
CONSCRYPT_NATIVE_METHOD(SSL_ECH_KEYS_free, "(J)V"),
CONSCRYPT_NATIVE_METHOD(SSL_ech_accepted, "(J" REF_SSL ")Z"),
CONSCRYPT_NATIVE_METHOD(SSL_CTX_ech_enable_server, "(J" REF_SSL_CTX "[B[B)Z"),

// Used for testing only.
CONSCRYPT_NATIVE_METHOD(BIO_read, "(J[B)I"),
CONSCRYPT_NATIVE_METHOD(BIO_write, "(J[BII)V"),
Expand Down
26 changes: 26 additions & 0 deletions common/src/main/java/org/conscrypt/NativeCrypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,32 @@ static native byte[] Scrypt_generate_key(
*/
static native boolean usesBoringSsl_FIPS_mode();

/* ECH */

static native void SSL_set_enable_ech_grease(long ssl, NativeSsl ssl_holder, boolean enable);

static native boolean SSL_set1_ech_config_list(
long ssl, NativeSsl ssl_holder, byte[] echConfig);

static native String SSL_get0_ech_name_override(long ssl, NativeSsl ssl_holder);

static native byte[] SSL_get0_ech_retry_configs(long ssl, NativeSsl ssl_holder);

static native byte[] SSL_marshal_ech_config(short configId, byte[] key, String publicName);

static native long SSL_ECH_KEYS_new();

static native void SSL_ECH_KEYS_up_ref(long sslEchKeys);

static native void SSL_ECH_KEYS_free(long sslEchKeys);

static native byte[] SSL_ECH_KEYS_marshal_retry_configs(byte[] key);

static native boolean SSL_ech_accepted(long ssl, NativeSsl ssl_holder);

static native boolean SSL_CTX_ech_enable_server(
long sslCtx, AbstractSessionContext holder, byte[] key, byte[] config);

/**
* Used for testing only.
*/
Expand Down
9 changes: 9 additions & 0 deletions openjdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,15 @@ def testInterop = tasks.register("testInterop", Test) {
}
check.dependsOn testInterop

// Added to see results of new ECH tests when running tests from the command line
tasks.withType(Test).configureEach {
testLogging {
exceptionFormat "full"
events "started", "skipped", "passed", "failed"
showStandardStreams true
}
}

jacocoTestReport {
additionalSourceDirs.from files("$rootDir/openjdk/src/test/java", "$rootDir/common/src/main/java")
executionData tasks.withType(Test)
Expand Down
Loading
Loading