Skip to content

Commit 2645b84

Browse files
committed
wire up ECH functions from boringssl
1 parent 5a9b7d2 commit 2645b84

15 files changed

+566
-0
lines changed

common/src/jni/main/cpp/conscrypt/native_crypto.cc

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <openssl/err.h>
4545
#include <openssl/evp.h>
4646
#include <openssl/hmac.h>
47+
#include <openssl/hpke.h>
4748
#include <openssl/pkcs7.h>
4849
#include <openssl/pkcs8.h>
4950
#include <openssl/rand.h>
@@ -123,6 +124,15 @@ static SSL_CIPHER* to_SSL_CIPHER(JNIEnv* env, jlong ssl_cipher_address, bool thr
123124
return ssl_cipher;
124125
}
125126

127+
static SSL_ECH_KEYS* to_SSL_ECH_KEYS(JNIEnv* env, jlong ssl_ech_keys_address, bool throwIfNull) {
128+
SSL_ECH_KEYS* ssl_ech_keys = reinterpret_cast<SSL_ECH_KEYS*>(static_cast<uintptr_t>(ssl_ech_keys_address));
129+
if ((ssl_ech_keys == nullptr) && throwIfNull) {
130+
JNI_TRACE("ssl_ech_keys == null");
131+
conscrypt::jniutil::throwNullPointerException(env, "ssl_ech_keys == null");
132+
}
133+
return ssl_ech_keys;
134+
}
135+
126136
template <typename T>
127137
static T* fromContextObject(JNIEnv* env, jobject contextObject) {
128138
if (contextObject == nullptr) {
@@ -10429,6 +10439,96 @@ static jlong NativeCrypto_SSL_get1_session(JNIEnv* env, jclass, jlong ssl_addres
1042910439
return reinterpret_cast<uintptr_t>(SSL_get1_session(ssl));
1043010440
}
1043110441

10442+
static void NativeCrypto_SSL_set_enable_ech_grease(JNIEnv* env, jclass, jlong ssl_address,
10443+
CONSCRYPT_UNUSED jobject ssl_holder,
10444+
jboolean enable) {
10445+
CHECK_ERROR_QUEUE_ON_RETURN;
10446+
SSL* ssl = to_SSL(env, ssl_address, true);
10447+
JNI_TRACE("ssl=%p NativeCrypto_SSL_set_enable_ech_grease(%d)", ssl, enable);
10448+
if (ssl == nullptr) {
10449+
return;
10450+
}
10451+
SSL_set_enable_ech_grease(ssl, enable ? 1 : 0);
10452+
JNI_TRACE("ssl=%p NativeCrypto_SSL_set_enable_ech_grease(%d) => success", ssl, enable);
10453+
}
10454+
10455+
static jboolean NativeCrypto_SSL_set1_ech_config_list(JNIEnv* env, jclass, jlong ssl_address,
10456+
CONSCRYPT_UNUSED jobject ssl_holder,
10457+
jbyteArray configJavaBytes) {
10458+
CHECK_ERROR_QUEUE_ON_RETURN;
10459+
SSL* ssl = to_SSL(env, ssl_address, true);
10460+
JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p)", ssl, configJavaBytes);
10461+
if (ssl == nullptr) {
10462+
return JNI_FALSE;
10463+
}
10464+
ScopedByteArrayRO configBytes(env, configJavaBytes);
10465+
if (configBytes.get() == nullptr) {
10466+
JNI_TRACE("NativeCrypto_SSL_set1_ech_config_list => threw exception:"
10467+
" could not read config bytes");
10468+
return JNI_FALSE;
10469+
}
10470+
const uint8_t* bs = reinterpret_cast<const uint8_t*>(configBytes.get());
10471+
int ret = SSL_set1_ech_config_list(ssl, reinterpret_cast<const uint8_t*>(configBytes.get()),
10472+
configBytes.size());
10473+
JNI_TRACE("ssl=%p NativeCrypto_SSL_set1_ech_config_list(%p) => %d", ssl, configJavaBytes, ret);
10474+
return !!ret;
10475+
}
10476+
10477+
/**
10478+
* public static native long SSL_ech_accepted(long ssl);
10479+
*/
10480+
static jboolean NativeCrypto_SSL_ech_accepted(JNIEnv* env, jclass, jlong ssl_address,
10481+
CONSCRYPT_UNUSED jobject ssl_holder) {
10482+
JNI_TRACE("NativeCrypto_SSL_ech_accepted");
10483+
CHECK_ERROR_QUEUE_ON_RETURN;
10484+
SSL* ssl = to_SSL(env, ssl_address, true);
10485+
JNI_TRACE("ssl=%p NativeCrypto_SSL_ech_accepted", ssl);
10486+
if (ssl == nullptr) {
10487+
return 0;
10488+
}
10489+
jboolean accepted = SSL_ech_accepted(ssl);
10490+
JNI_TRACE("ssl=%p NativeCrypto_SSL_ech_accepted => %d", ssl, accepted);
10491+
return accepted;
10492+
}
10493+
10494+
static jboolean NativeCrypto_SSL_CTX_ech_enable_server(JNIEnv* env, jclass, jlong ssl_ctx_address,
10495+
CONSCRYPT_UNUSED jobject holder,
10496+
jbyteArray keyJavaBytes,
10497+
jbyteArray configJavaBytes) {
10498+
CHECK_ERROR_QUEUE_ON_RETURN;
10499+
SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
10500+
JNI_TRACE("NativeCrypto_SSL_CTX_ech_enable_server(keyJavaBytes=%p, configJavaBytes=%p)",
10501+
keyJavaBytes, configJavaBytes);
10502+
ScopedByteArrayRO keyBytes(env, keyJavaBytes);
10503+
if (keyBytes.get() == nullptr) {
10504+
JNI_TRACE("NativeCrypto_SSL_CTX_ech_enable_server => threw exception: "
10505+
"could not read key bytes");
10506+
return JNI_FALSE;
10507+
}
10508+
ScopedByteArrayRO configBytes(env, configJavaBytes);
10509+
if (configBytes.get() == nullptr) {
10510+
JNI_TRACE("NativeCrypto_SSL_CTX_ech_enable_server => threw exception: "
10511+
"could not read config bytes");
10512+
return JNI_FALSE;
10513+
}
10514+
const uint8_t* ech_key = reinterpret_cast<const uint8_t*>(keyBytes.get());
10515+
size_t ech_key_size = keyBytes.size();
10516+
const uint8_t* ech_config = reinterpret_cast<const uint8_t*>(configBytes.get());
10517+
size_t ech_config_size = configBytes.size();
10518+
bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
10519+
bssl::ScopedEVP_HPKE_KEY key;
10520+
if (!keys ||
10521+
!EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(), ech_key, ech_key_size) ||
10522+
!SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
10523+
ech_config, ech_config_size, key.get()) ||
10524+
!SSL_CTX_set1_ech_keys(ssl_ctx, keys.get())) {
10525+
JNI_TRACE("NativeCrypto_SSL_CTX_ech_enable_server: "
10526+
"Error setting server's ECHConfig and private key\n");
10527+
return JNI_FALSE;
10528+
}
10529+
return JNI_TRUE;
10530+
}
10531+
1043210532
// TESTING METHODS END
1043310533

1043410534
#define CONSCRYPT_NATIVE_METHOD(functionName, signature) \
@@ -10749,6 +10849,10 @@ static JNINativeMethod sNativeCryptoMethods[] = {
1074910849
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_force_read, "(J" REF_SSL SSL_CALLBACKS ")V"),
1075010850
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_shutdown, "(J" REF_SSL SSL_CALLBACKS ")V"),
1075110851
CONSCRYPT_NATIVE_METHOD(usesBoringSsl_FIPS_mode, "()Z"),
10852+
CONSCRYPT_NATIVE_METHOD(SSL_set_enable_ech_grease, "(J" REF_SSL "Z)V"),
10853+
CONSCRYPT_NATIVE_METHOD(SSL_set1_ech_config_list, "(J" REF_SSL "[B)Z"),
10854+
CONSCRYPT_NATIVE_METHOD(SSL_ech_accepted, "(J" REF_SSL ")Z"),
10855+
CONSCRYPT_NATIVE_METHOD(SSL_CTX_ech_enable_server, "(J" REF_SSL_CTX "[B[B)Z"),
1075210856
1075310857
// Used for testing only.
1075410858
CONSCRYPT_NATIVE_METHOD(BIO_read, "(J[B)I"),

common/src/main/java/org/conscrypt/AbstractConscryptEngine.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ abstract class AbstractConscryptEngine extends SSLEngine {
9292

9393
@Override public abstract int getPeerPort();
9494

95+
public abstract void setUseEchGrease(boolean enabled);
96+
97+
public abstract boolean getUseEchGrease();
98+
99+
public abstract void setEchConfigList(byte[] echConfigList);
100+
101+
public abstract byte[] getEchConfigList();
102+
103+
public abstract boolean echAccepted();
104+
95105
/* @Override */
96106
@SuppressWarnings("MissingOverride") // For compilation with Java 6.
97107
public final SSLSession getHandshakeSession() {

common/src/main/java/org/conscrypt/AbstractConscryptSocket.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,4 +754,12 @@ void setNpnProtocols(byte[] npnProtocols) {}
754754
*/
755755
abstract byte[] exportKeyingMaterial(String label, byte[] context, int length)
756756
throws SSLException;
757+
758+
public abstract void setUseEchGrease(boolean enabled);
759+
760+
public abstract void setEchConfigList(byte[] echConfigList);
761+
762+
public abstract byte[] getEchConfigList();
763+
764+
public abstract boolean echAccepted();
757765
}

common/src/main/java/org/conscrypt/Conscrypt.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,27 @@ public static byte[] exportKeyingMaterial(SSLSocket socket, String label, byte[]
493493
return toConscrypt(socket).exportKeyingMaterial(label, context, length);
494494
}
495495

496+
/**
497+
*
498+
* @param socket the socket
499+
* @param enabled whether ECH GREASE is enabled or not
500+
*/
501+
public static void setUseEchGrease(SSLSocket socket, boolean enabled) {
502+
toConscrypt(socket).setUseEchGrease(enabled);
503+
}
504+
505+
public static void setEchConfigList(SSLSocket socket, byte[] echConfigList) {
506+
toConscrypt(socket).setEchConfigList(echConfigList);
507+
}
508+
509+
public static byte[] getEchConfigList(SSLSocket socket) {
510+
return toConscrypt(socket).getEchConfigList();
511+
}
512+
513+
public static boolean echAccepted(SSLSocket socket) {
514+
return toConscrypt(socket).echAccepted();
515+
}
516+
496517
/**
497518
* Indicates whether the given {@link SSLEngine} was created by this distribution of Conscrypt.
498519
*/
@@ -737,6 +758,30 @@ public static byte[] exportKeyingMaterial(SSLEngine engine, String label, byte[]
737758
return toConscrypt(engine).exportKeyingMaterial(label, context, length);
738759
}
739760

761+
/**
762+
* This method enables or disables Encrypted Client Hello (ECH) GREASE.
763+
*
764+
* @param engine the engine
765+
* @param enabled Whether to enable TLSv1.3 ECH GREASE
766+
*
767+
* @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>
768+
*/
769+
public static void setUseEchGrease(SSLEngine engine, boolean enabled) {
770+
toConscrypt(engine).setUseEchGrease(enabled);
771+
}
772+
773+
public static void setEchConfigList(SSLEngine engine, byte[] echConfigList) {
774+
toConscrypt(engine).setEchConfigList(echConfigList);
775+
}
776+
777+
public static byte[] getEchConfigList(SSLEngine engine) {
778+
return toConscrypt(engine).getEchConfigList();
779+
}
780+
781+
public static boolean echAccepted(SSLEngine engine) {
782+
return toConscrypt(engine).echAccepted();
783+
}
784+
740785
/**
741786
* Indicates whether the given {@link TrustManager} was created by this distribution of
742787
* Conscrypt.

common/src/main/java/org/conscrypt/ConscryptEngine.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,31 @@ public int getPeerPort() {
395395
return peerInfoProvider.getPort();
396396
}
397397

398+
@Override
399+
public void setUseEchGrease(boolean enabled) {
400+
sslParameters.setUseEchGrease(enabled);
401+
}
402+
403+
@Override
404+
public boolean getUseEchGrease() {
405+
return sslParameters.getUseEchGrease();
406+
}
407+
408+
@Override
409+
public void setEchConfigList(byte[] echConfigList) {
410+
sslParameters.setEchConfigList(echConfigList);
411+
}
412+
413+
@Override
414+
public byte[] getEchConfigList() {
415+
return sslParameters.getEchConfigList();
416+
}
417+
418+
@Override
419+
public boolean echAccepted() {
420+
return ssl.echAccepted();
421+
}
422+
398423
@Override
399424
public void beginHandshake() throws SSLException {
400425
synchronized (ssl) {

common/src/main/java/org/conscrypt/ConscryptEngineSocket.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,26 @@ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSL
405405
return engine.exportKeyingMaterial(label, context, length);
406406
}
407407

408+
@Override
409+
public void setUseEchGrease(boolean enabled) {
410+
engine.setUseEchGrease(enabled);
411+
}
412+
413+
@Override
414+
public void setEchConfigList(byte[] echConfigList) {
415+
engine.setEchConfigList(echConfigList);
416+
}
417+
418+
@Override
419+
public byte[] getEchConfigList() {
420+
return engine.getEchConfigList();
421+
}
422+
423+
@Override
424+
public boolean echAccepted() {
425+
return engine.echAccepted();
426+
}
427+
408428
@Override
409429
public final boolean getUseClientMode() {
410430
return engine.getUseClientMode();

common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,26 @@ byte[] exportKeyingMaterial(String label, byte[] context, int length) throws SSL
916916
return ssl.exportKeyingMaterial(label, context, length);
917917
}
918918

919+
@Override
920+
public void setUseEchGrease(boolean enabled) {
921+
sslParameters.setUseEchGrease(enabled);
922+
}
923+
924+
@Override
925+
public void setEchConfigList(byte[] echConfigList) {
926+
sslParameters.setEchConfigList(echConfigList);
927+
}
928+
929+
@Override
930+
public byte[] getEchConfigList() {
931+
return sslParameters.getEchConfigList();
932+
}
933+
934+
@Override
935+
public boolean echAccepted() {
936+
return ssl.echAccepted();
937+
}
938+
919939
@Override
920940
public final boolean getUseClientMode() {
921941
return sslParameters.getUseClientMode();

common/src/main/java/org/conscrypt/Java8EngineWrapper.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,31 @@ public int getPeerPort() {
116116
return delegate.getPeerPort();
117117
}
118118

119+
@Override
120+
public void setUseEchGrease(boolean enabled) {
121+
delegate.setUseEchGrease(enabled);
122+
}
123+
124+
@Override
125+
public boolean getUseEchGrease() {
126+
return delegate.getUseEchGrease();
127+
}
128+
129+
@Override
130+
public void setEchConfigList(byte[] echConfigList) {
131+
delegate.setEchConfigList(echConfigList);
132+
}
133+
134+
@Override
135+
public byte[] getEchConfigList() {
136+
return delegate.getEchConfigList();
137+
}
138+
139+
@Override
140+
public boolean echAccepted() {
141+
return delegate.echAccepted();
142+
}
143+
119144
@Override
120145
public void beginHandshake() throws SSLException {
121146
delegate.beginHandshake();

common/src/main/java/org/conscrypt/NativeCrypto.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,17 @@ static native void ENGINE_SSL_shutdown(long ssl, NativeSsl ssl_holder, SSLHandsh
14481448
*/
14491449
static native boolean usesBoringSsl_FIPS_mode();
14501450

1451+
/* Encrypted Client Hello */
1452+
1453+
static native void SSL_set_enable_ech_grease(long ssl, NativeSsl ssl_holder, boolean enable);
1454+
1455+
static native boolean SSL_set1_ech_config_list(long ssl, NativeSsl ssl_holder, byte[] echConfig);
1456+
1457+
static native boolean SSL_ech_accepted(long ssl, NativeSsl ssl_holder);
1458+
1459+
static native boolean SSL_CTX_ech_enable_server(long sslCtx, AbstractSessionContext holder,
1460+
byte[] key, byte[] config);
1461+
14511462
/**
14521463
* Used for testing only.
14531464
*/

common/src/main/java/org/conscrypt/NativeSsl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ byte[] getTlsChannelId() throws SSLException {
279279
return NativeCrypto.SSL_get_tls_channel_id(ssl, this);
280280
}
281281

282+
boolean echAccepted() {
283+
return NativeCrypto.SSL_ech_accepted(ssl, this);
284+
}
285+
282286
void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
283287
boolean enableSessionCreation = parameters.getEnableSessionCreation();
284288
if (!enableSessionCreation) {
@@ -298,6 +302,11 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
298302
if (parameters.isCTVerificationEnabled(hostname)) {
299303
NativeCrypto.SSL_enable_signed_cert_timestamps(ssl, this);
300304
}
305+
NativeCrypto.SSL_set_enable_ech_grease(ssl, this, parameters.getUseEchGrease());
306+
if (parameters.echConfigList != null
307+
&& !NativeCrypto.SSL_set1_ech_config_list(ssl, this, parameters.echConfigList)) {
308+
throw new SSLHandshakeException("Error setting ECHConfigList");
309+
}
301310
} else {
302311
NativeCrypto.SSL_set_accept_state(ssl, this);
303312

0 commit comments

Comments
 (0)