Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions openssl-classes/src/main/java/io/netty/internal/tcnative/SSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,32 @@ public static void setTlsExtHostName(long ssl, String hostname) {
*/
public static native String[] authenticationMethods(long ssl);

/**
* Return the authentication methods packed into an {@code int}, avoiding {@code String[]} allocation.
* Each bit corresponds to an OpenSSL {@code SSL_a*} authentication constant (see sslutils.c):
* <p>
* Common (produced by all code paths):
* <ul>
* <li>{@code 0x0001} (SSL_aRSA) - RSA authentication (RSA, DHE_RSA, ECDHE_RSA)</li>
* <li>{@code 0x0002} (SSL_aDSS) - DSS authentication (DHE_DSS)</li>
* <li>{@code 0x0004} (SSL_aNULL) - no auth / anonymous (DH_anon, ECDH_anon)</li>
* <li>{@code 0x0040} (SSL_aECDSA) - ECDSA authentication (ECDHE_ECDSA)</li>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm wondering is if we should expose these constants through static fields in SSL, initialized from NativeStaticallyReferencedJniMethods calls.

@doom369 doom369 Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's a good idea actually, minimizes the chance for error.

* </ul>
* Legacy (only possible on OpenSSL &lt; 1.1.0):
* <ul>
* <li>{@code 0x0008} (SSL_aDH) - Fixed DH auth</li>
* <li>{@code 0x0010} (SSL_aECDH) - Fixed ECDH auth</li>
* <li>{@code 0x0020} (SSL_aKRB5) - KRB5 auth</li>
* <li>{@code 0x0080} (SSL_aPSK) - PSK auth</li>
* <li>{@code 0x0100} (SSL_aGOST94) - GOST R 34.10-94 auth</li>
* <li>{@code 0x0200} (SSL_aGOST01) - GOST R 34.10-2001 auth</li>
* </ul>
*
* @param ssl the SSL instance (SSL*)
* @return the packed authentication methods as a bitmask
*/
public static native int authenticationMethodsPacked(long ssl);

/**
* Set BIO of PEM-encoded Server CA Certificates
* <p>
Expand Down
102 changes: 102 additions & 0 deletions openssl-dynamic/src/main/c/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,107 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, authenticationMethods)(TCN_STDARGS, jlong
return array;
}

/* Bits for algorithm_auth, same as defined in sslutils.c */
#define TCN_SSL_aRSA 0x00000001L
#define TCN_SSL_aDSS 0x00000002L
#define TCN_SSL_aNULL 0x00000004L
#define TCN_SSL_aECDSA 0x00000040L
#define TCN_SSL_aALL (TCN_SSL_aRSA | TCN_SSL_aDSS | TCN_SSL_aNULL | TCN_SSL_aECDSA)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not great to define them again. Maybe they can be moved to ssl_private.h?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll check


/**
* Returns authentication methods packed into an int, avoiding String[] allocation.
* Uses the same bit values as OpenSSL's algorithm_auth constants (see sslutils.c):
*
* Common (produced by all code paths):
* 0x0001 (SSL_aRSA) - RSA authentication (RSA, DHE_RSA, ECDHE_RSA)
* 0x0002 (SSL_aDSS) - DSS authentication (DHE_DSS)
* 0x0004 (SSL_aNULL) - no auth / anonymous (DH_anon, ECDH_anon)
* 0x0040 (SSL_aECDSA) - ECDSA authentication (ECDHE_ECDSA)
*
* Legacy (only possible on OpenSSL < 1.1.0, passed through from algorithm_auth):
* 0x0008 (SSL_aDH) - Fixed DH auth
* 0x0010 (SSL_aECDH) - Fixed ECDH auth
* 0x0020 (SSL_aKRB5) - KRB5 auth
* 0x0080 (SSL_aPSK) - PSK auth
* 0x0100 (SSL_aGOST94) - GOST R 34.10-94 auth
* 0x0200 (SSL_aGOST01) - GOST R 34.10-2001 auth
*/
TCN_IMPLEMENT_CALL(jint, SSL, authenticationMethodsPacked)(TCN_STDARGS, jlong ssl) {
SSL *ssl_ = J2P(ssl, SSL *);
const STACK_OF(SSL_CIPHER) *ciphers = NULL;
int len;
int i;
jint packed = 0;

TCN_CHECK_NULL(ssl_, ssl, 0);

ciphers = SSL_get_ciphers(ssl_);
len = sk_SSL_CIPHER_num(ciphers);

for (i = 0; i < len; i++) {
const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);

#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
// BoringSSL/AWS-LC: classify by exact kx_name
const char *name = SSL_CIPHER_get_kx_name(cipher);
if (name == NULL) {
continue;
}
// TLS 1.3 ciphers report "GENERIC" and appear first in the list — skip early
if (strcmp(name, "GENERIC") == 0) {
continue;
}
if (strcmp(name, "RSA") == 0 ||
strcmp(name, "DHE_RSA") == 0 ||
strcmp(name, "ECDHE_RSA") == 0) {
packed |= TCN_SSL_aRSA;
} else if (strcmp(name, "ECDHE_ECDSA") == 0) {
packed |= TCN_SSL_aECDSA;
} else if (strcmp(name, "DH_anon") == 0 ||
strcmp(name, "ECDH_anon") == 0) {
packed |= TCN_SSL_aNULL;
} else if (strcmp(name, "DHE_DSS") == 0) {
packed |= TCN_SSL_aDSS;
}
// All common bits set — no point continuing
if ((packed & TCN_SSL_aALL) == TCN_SSL_aALL) {
break;
}

#elif OPENSSL_VERSION_NUMBER >= 0x10100000L && (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
// OpenSSL 1.1.0+ / LibreSSL 2.7.0+: use NID-based API
switch (SSL_CIPHER_get_auth_nid(cipher)) {
case NID_auth_rsa:
packed |= TCN_SSL_aRSA;
break;
#ifndef LIBRESSL_VERSION_NUMBER
case NID_auth_dss:
packed |= TCN_SSL_aDSS;
break;
#endif
case NID_auth_null:
packed |= TCN_SSL_aNULL;
break;
case NID_auth_ecdsa:
packed |= TCN_SSL_aECDSA;
break;
}
// All common bits set — no point continuing
if ((packed & TCN_SSL_aALL) == TCN_SSL_aALL) {
break;
}

#else
// Older OpenSSL (< 1.1.0): read algorithm_auth directly from struct.
// May include legacy bits (SSL_aDH, SSL_aECDH, SSL_aKRB5, etc.)
// not produced by the BoringSSL/OpenSSL 1.1+ code paths above.
packed |= (jint) cipher->algorithm_auth;
#endif
}

return packed;
}

TCN_IMPLEMENT_CALL(void, SSL, setCertificateBio)(TCN_STDARGS, jlong ssl,
jlong cert, jlong key,
jstring password)
Expand Down Expand Up @@ -2761,6 +2862,7 @@ static const JNINativeMethod method_table[] = {
{ TCN_METHOD_TABLE_ENTRY(setTlsExtHostName0, (JLjava/lang/String;)V, SSL) },
{ TCN_METHOD_TABLE_ENTRY(setHostNameValidation, (JILjava/lang/String;)V, SSL) },
{ TCN_METHOD_TABLE_ENTRY(authenticationMethods, (J)[Ljava/lang/String;, SSL) },
{ TCN_METHOD_TABLE_ENTRY(authenticationMethodsPacked, (J)I, SSL) },
{ TCN_METHOD_TABLE_ENTRY(setCertificateBio, (JJJLjava/lang/String;)V, SSL) },
{ TCN_METHOD_TABLE_ENTRY(setCertificateChainBio, (JJZ)V, SSL) },
{ TCN_METHOD_TABLE_ENTRY(loadPrivateKeyFromEngine, (Ljava/lang/String;Ljava/lang/String;)J, SSL) },
Expand Down
Loading