Skip to content

Commit dda31e3

Browse files
author
Alex Choulos
committed
Cache SSL_CREDENTIAL selected during handshake so getSelectedCredential works post-handshake
SSL_get0_selected_credential reads the handshake state, which BoringSSL frees before SSL_do_handshake returns, so SSL.getSelectedCredential always returned 0 once the handshake completed. Sample the credential in ssl_info_callback on SSL_CB_HANDSHAKE_DONE, hold a ref in tcn_ssl_state_t and release it in free_ssl_state. On renegotiation the previous ref is released and replaced, so the cache reflects the most recent completed handshake. getSelectedCredential tries the live lookup first (non-NULL only while the handshake state exists) and falls back to the cached credential.
1 parent 91e525b commit dda31e3

4 files changed

Lines changed: 38 additions & 1 deletion

File tree

‎openssl-classes/src/main/java/io/netty/internal/tcnative/SSL.java‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,10 @@ public static AsyncTask getAsyncTask(long ssl) {
997997
* <p>This is a BoringSSL-specific feature. See
998998
* <a href="https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_get0_selected_credential">SSL_get0_selected_credential</a>
999999
* for detailed documentation.</p>
1000-
*
1000+
*
1001+
* <p>Once a handshake has completed this returns the credential selected during the most recent completed
1002+
* handshake. The returned pointer is borrowed and stays valid until {@link #freeSSL(long)}; do not free it.</p>
1003+
*
10011004
* @param ssl the SSL instance (SSL *)
10021005
* @return the selected credential (SSL_CREDENTIAL *) or {@code 0} if none
10031006
* @throws Exception if an error occurred

‎openssl-dynamic/src/main/c/ssl.c‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,13 @@ static void free_ssl_state(JNIEnv* e, tcn_ssl_state_t* state) {
933933
tcn_ssl_task_free(e, state->ssl_task);
934934
state->ssl_task = NULL;
935935

936+
#ifdef OPENSSL_IS_BORINGSSL
937+
if (state->selected_credential != NULL) {
938+
SSL_CREDENTIAL_free((SSL_CREDENTIAL*) state->selected_credential);
939+
state->selected_credential = NULL;
940+
}
941+
#endif
942+
936943
// Free the tcn_ssl_state_t itself as it was allocated via OPENSSL_malloc(...) before
937944
//
938945
// https://github.com/netty/netty-tcnative/issues/532
@@ -2763,6 +2770,13 @@ TCN_IMPLEMENT_CALL(jlong, SSL, getSelectedCredential)(TCN_STDARGS, jlong ssl) {
27632770
SSL *ssl_ = J2P(ssl, SSL *);
27642771
TCN_CHECK_NULL(ssl_, ssl, 0);
27652772
const SSL_CREDENTIAL* credential = SSL_get0_selected_credential(ssl_);
2773+
if (credential == NULL) {
2774+
// Handshake state is gone once the handshake completed, use the credential cached by ssl_info_callback.
2775+
tcn_ssl_state_t* state = tcn_SSL_get_app_state(ssl_);
2776+
if (state != NULL) {
2777+
credential = state->selected_credential;
2778+
}
2779+
}
27662780
if (credential == NULL) {
27672781
return 0;
27682782
}

‎openssl-dynamic/src/main/c/ssl_private.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ struct tcn_ssl_state_t {
411411
// len < sk_CRYPTO_BUFFER_num(chain) check (both locals are 0/NULL there).
412412
int task_array_len;
413413
int task_chain_num;
414+
#ifdef OPENSSL_IS_BORINGSSL
415+
// Ref-counted credential sampled in SSL_CB_HANDSHAKE_DONE, as the selection is gone once the handshake completes.
416+
const SSL_CREDENTIAL *selected_credential;
417+
#endif
414418
};
415419

416420
#define TCN_GET_SSL_CTX(ssl, C) \

‎openssl-dynamic/src/main/c/sslcontext.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,22 @@ static void ssl_info_callback(const SSL *ssl, int where, int ret) {
189189
state->handshakeCount++;
190190
}
191191
}
192+
#ifdef OPENSSL_IS_BORINGSSL
193+
if (0 != (where & SSL_CB_HANDSHAKE_DONE)) {
194+
// The selection lives in the handshake state, which BoringSSL frees before SSL_do_handshake returns, so it
195+
// must be sampled here. On renegotiation the previous ref is replaced by the most recent selection.
196+
if ((state = tcn_SSL_get_app_state(ssl)) != NULL) {
197+
const SSL_CREDENTIAL* credential = SSL_get0_selected_credential(ssl);
198+
if (credential != NULL) {
199+
SSL_CREDENTIAL_up_ref((SSL_CREDENTIAL*) credential);
200+
if (state->selected_credential != NULL) {
201+
SSL_CREDENTIAL_free((SSL_CREDENTIAL*) state->selected_credential);
202+
}
203+
state->selected_credential = credential;
204+
}
205+
}
206+
}
207+
#endif
192208
}
193209

194210
/* Initialize server context */

0 commit comments

Comments
 (0)