Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c9968c0
wire up ECH functions from boringssl
eighthave Sep 17, 2021
3ae5bd7
implement ECH Retry Config handling
eighthave Nov 10, 2021
e39aca1
use Android DnsPacket to implement DNS using JNDI/DnsResolver
eighthave Oct 21, 2021
dcbddbb
hack in Exception to handle "ECH_REJECTED" and Retry Configs
eighthave Nov 17, 2021
b1a6773
gradlew: add distributionSha256Sum to verify download
eighthave May 11, 2021
50f54ed
Convenient debug print for ECH Config Lists
eighthave Nov 10, 2021
cb3fb9c
EchInteropTest
eighthave Nov 10, 2021
7ed0dd3
add .gitlab-ci.yml
eighthave Oct 15, 2019
37198ff
additional tests that trigger AssertionError with checkErrorQueue
eighthave Nov 12, 2021
c3a1454
WIP implement full server ECH API
eighthave Nov 10, 2021
0f2c303
changes to resolve compile issues
mnbogner May 12, 2025
e4bf0ab
Merge branch 'master' of https://github.com/google/conscrypt into mas…
mnbogner May 12, 2025
679e4ec
Merge branch 'master' of https://github.com/eighthave/conscrypt into …
mnbogner May 13, 2025
e9de453
fixing several compile errors
mnbogner May 14, 2025
3235c53
restore missing test code
mnbogner May 15, 2025
4cb4ebd
revised test cases to handle exceptions better and print louder log m…
mnbogner May 23, 2025
5bb8514
revert changes required for local build issues
mnbogner May 26, 2025
a7de26c
revised tests to use live dns results instead of parsed files
mnbogner May 31, 2025
1481f4b
replace parameters with parameter object
mnbogner Jun 3, 2025
23ba5bb
fleshed out Conscrypt method descriptions based on feedback
mnbogner Jun 11, 2025
d24922d
Merge branch 'master' of https://github.com/google/conscrypt into bas…
mnbogner Jun 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
wire up ECH functions from boringssl
  • Loading branch information
eighthave committed Nov 12, 2021
commit c9968c0654a4f6fdd609cb541eec4eb59a4213a3
104 changes: 104 additions & 0 deletions common/src/jni/main/cpp/conscrypt/native_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/hpke.h>
#include <openssl/pkcs7.h>
#include <openssl/pkcs8.h>
#include <openssl/rand.h>
Expand Down Expand Up @@ -123,6 +124,15 @@ 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 @@ -10429,6 +10439,96 @@ 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) {
return JNI_FALSE;
}
ScopedByteArrayRO configBytes(env, configJavaBytes);
if (configBytes.get() == nullptr) {
JNI_TRACE("NativeCrypto_SSL_set1_ech_config_list => threw exception:"
" could not read config bytes");
return JNI_FALSE;
}
const uint8_t* bs = reinterpret_cast<const uint8_t*>(configBytes.get());
int ret = SSL_set1_ech_config_list(ssl, reinterpret_cast<const uint8_t*>(configBytes.get()),
configBytes.size());
JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p) => %d", ssl, configJavaBytes, ret);
return !!ret;
}

/**
* public static native long SSL_ech_accepted(long ssl);
*/
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) {
return 0;
}
jboolean accepted = SSL_ech_accepted(ssl);
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) {
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) {
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())) {
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 @@ -10749,6 +10849,10 @@ static JNINativeMethod sNativeCryptoMethods[] = {
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_force_read, "(J" REF_SSL SSL_CALLBACKS ")V"),
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_shutdown, "(J" REF_SSL SSL_CALLBACKS ")V"),
CONSCRYPT_NATIVE_METHOD(usesBoringSsl_FIPS_mode, "()Z"),
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_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"),
Expand Down
10 changes: 10 additions & 0 deletions common/src/main/java/org/conscrypt/AbstractConscryptEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ abstract class AbstractConscryptEngine extends SSLEngine {

@Override public abstract int getPeerPort();

public abstract void setUseEchGrease(boolean enabled);

public abstract boolean getUseEchGrease();

public abstract void setEchConfigList(byte[] echConfigList);

public abstract byte[] getEchConfigList();

public abstract boolean echAccepted();

/* @Override */
@SuppressWarnings("MissingOverride") // For compilation with Java 6.
public final SSLSession getHandshakeSession() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,4 +754,12 @@ void setNpnProtocols(byte[] npnProtocols) {}
*/
abstract byte[] exportKeyingMaterial(String label, byte[] context, int length)
throws SSLException;

public abstract void setUseEchGrease(boolean enabled);

public abstract void setEchConfigList(byte[] echConfigList);

public abstract byte[] getEchConfigList();

public abstract boolean echAccepted();
}
45 changes: 45 additions & 0 deletions common/src/main/java/org/conscrypt/Conscrypt.java
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,27 @@ public static byte[] exportKeyingMaterial(SSLSocket socket, String label, byte[]
return toConscrypt(socket).exportKeyingMaterial(label, context, length);
}

/**
*
* @param socket the socket
* @param enabled whether ECH GREASE is enabled or not
Copy link

Choose a reason for hiding this comment

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

I believe this needs to be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call, I fixed this and also added descriptions for the other new methods in Conscrypt.java.

*/
public static void setUseEchGrease(SSLSocket socket, boolean enabled) {
toConscrypt(socket).setUseEchGrease(enabled);
}

public static void setEchConfigList(SSLSocket socket, byte[] echConfigList) {
toConscrypt(socket).setEchConfigList(echConfigList);
}

public static byte[] getEchConfigList(SSLSocket socket) {
return toConscrypt(socket).getEchConfigList();
}

public static boolean echAccepted(SSLSocket socket) {
return toConscrypt(socket).echAccepted();
}

/**
* Indicates whether the given {@link SSLEngine} was created by this distribution of Conscrypt.
*/
Expand Down Expand Up @@ -737,6 +758,30 @@ public static byte[] exportKeyingMaterial(SSLEngine engine, String label, byte[]
return toConscrypt(engine).exportKeyingMaterial(label, context, length);
}

/**
* This method enables or disables Encrypted Client Hello (ECH) GREASE.
*
* @param engine the engine
* @param enabled Whether to enable TLSv1.3 ECH GREASE
*
* @see <a href="https://www.ietf.org/archive/id/draft-ietf-tls-esni-13.html#section-6.2">TLS Encrypted Client Hello 6.2. GREASE ECH</a>
*/
public static void setUseEchGrease(SSLEngine engine, boolean enabled) {
toConscrypt(engine).setUseEchGrease(enabled);
}

public static void setEchConfigList(SSLEngine engine, byte[] echConfigList) {
toConscrypt(engine).setEchConfigList(echConfigList);
}

public static byte[] getEchConfigList(SSLEngine engine) {
return toConscrypt(engine).getEchConfigList();
}

public static boolean echAccepted(SSLEngine engine) {
return toConscrypt(engine).echAccepted();
}

/**
* Indicates whether the given {@link TrustManager} was created by this distribution of
* Conscrypt.
Expand Down
25 changes: 25 additions & 0 deletions common/src/main/java/org/conscrypt/ConscryptEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,31 @@ public int getPeerPort() {
return peerInfoProvider.getPort();
}

@Override
public void setUseEchGrease(boolean enabled) {
sslParameters.setUseEchGrease(enabled);
}

@Override
public boolean getUseEchGrease() {
return sslParameters.getUseEchGrease();
}

@Override
public void setEchConfigList(byte[] echConfigList) {
sslParameters.setEchConfigList(echConfigList);
}

@Override
public byte[] getEchConfigList() {
return sslParameters.getEchConfigList();
}

@Override
public boolean echAccepted() {
return ssl.echAccepted();
}

@Override
public void beginHandshake() throws SSLException {
synchronized (ssl) {
Expand Down
20 changes: 20 additions & 0 deletions common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,26 @@ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSL
return engine.exportKeyingMaterial(label, context, length);
}

@Override
public void setUseEchGrease(boolean enabled) {
engine.setUseEchGrease(enabled);
}

@Override
public void setEchConfigList(byte[] echConfigList) {
engine.setEchConfigList(echConfigList);
}

@Override
public byte[] getEchConfigList() {
return engine.getEchConfigList();
}

@Override
public boolean echAccepted() {
return engine.echAccepted();
}

@Override
public final boolean getUseClientMode() {
return engine.getUseClientMode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,26 @@ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSL
return ssl.exportKeyingMaterial(label, context, length);
}

@Override
public void setUseEchGrease(boolean enabled) {
sslParameters.setUseEchGrease(enabled);
}

@Override
public void setEchConfigList(byte[] echConfigList) {
sslParameters.setEchConfigList(echConfigList);
}

@Override
public byte[] getEchConfigList() {
return sslParameters.getEchConfigList();
}

@Override
public boolean echAccepted() {
return ssl.echAccepted();
}

@Override
public final boolean getUseClientMode() {
return sslParameters.getUseClientMode();
Expand Down
25 changes: 25 additions & 0 deletions common/src/main/java/org/conscrypt/Java8EngineWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,31 @@ public int getPeerPort() {
return delegate.getPeerPort();
}

@Override
public void setUseEchGrease(boolean enabled) {
delegate.setUseEchGrease(enabled);
}

@Override
public boolean getUseEchGrease() {
return delegate.getUseEchGrease();
}

@Override
public void setEchConfigList(byte[] echConfigList) {
delegate.setEchConfigList(echConfigList);
}

@Override
public byte[] getEchConfigList() {
return delegate.getEchConfigList();
}

@Override
public boolean echAccepted() {
return delegate.echAccepted();
}

@Override
public void beginHandshake() throws SSLException {
delegate.beginHandshake();
Expand Down
11 changes: 11 additions & 0 deletions common/src/main/java/org/conscrypt/NativeCrypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,17 @@ static native void ENGINE_SSL_shutdown(long ssl, NativeSsl ssl_holder, SSLHandsh
*/
static native boolean usesBoringSsl_FIPS_mode();

/* Encrypted Client Hello */

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 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 common/src/main/java/org/conscrypt/NativeSsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ byte[] getTlsChannelId() throws SSLException {
return NativeCrypto.SSL_get_tls_channel_id(ssl, this);
}

boolean echAccepted() {
return NativeCrypto.SSL_ech_accepted(ssl, this);
}

void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
boolean enableSessionCreation = parameters.getEnableSessionCreation();
if (!enableSessionCreation) {
Expand All @@ -298,6 +302,11 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
if (parameters.isCTVerificationEnabled(hostname)) {
NativeCrypto.SSL_enable_signed_cert_timestamps(ssl, this);
}
NativeCrypto.SSL_set_enable_ech_grease(ssl, this, parameters.getUseEchGrease());
if (parameters.echConfigList != null
&& !NativeCrypto.SSL_set1_ech_config_list(ssl, this, parameters.echConfigList)) {
throw new SSLHandshakeException("Error setting ECHConfigList");
}
} else {
NativeCrypto.SSL_set_accept_state(ssl, this);

Expand Down
Loading