Skip to content

Commit bb97579

Browse files
committed
add support for SSLEngine.getApplicationProtocol
1 parent 59afb97 commit bb97579

10 files changed

Lines changed: 319 additions & 19 deletions

native/com_wolfssl_WolfSSL.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

native/com_wolfssl_WolfSSLSession.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3676,7 +3676,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sslSetAlpnProtos
36763676
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray alpnProtos)
36773677
{
36783678
int ret = SSL_FAILURE;
3679-
#ifdef HAVE_ALPN
3679+
(void)jcl;
3680+
#if defined(HAVE_ALPN) && (LIBWOLFSSL_VERSION_HEX >= 0x04002000)
3681+
/* wolfSSL_set_alpn_protos() added as of wolfSSL 4.2.0 */
36803682
byte* buff = NULL;
36813683
word32 buffSz = 0;
36823684
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
@@ -3753,6 +3755,35 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_sslGet0AlpnSelected
37533755
#endif
37543756
}
37553757

3758+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useALPN
3759+
(JNIEnv* jenv, jobject jcl, jlong ssl, jstring protocols, jint options)
3760+
{
3761+
int ret = SSL_FAILURE;
3762+
(void)jcl;
3763+
#ifdef HAVE_ALPN
3764+
const char* protoList;
3765+
3766+
if (jenv == NULL || ssl == 0 || protocols == NULL || options < 0) {
3767+
return BAD_FUNC_ARG;
3768+
}
3769+
3770+
protoList = (*jenv)->GetStringUTFChars(jenv, protocols, 0);
3771+
3772+
ret = (jint) wolfSSL_UseALPN((WOLFSSL*)(uintptr_t)ssl, (char*)protoList,
3773+
XSTRLEN(protoList), (int)options);
3774+
3775+
(*jenv)->ReleaseStringUTFChars(jenv, protocols, protoList);
3776+
#else
3777+
(void)jenv;
3778+
(void)ssl;
3779+
(void)protocols;
3780+
(void)options;
3781+
ret = NOT_COMPILED_IN;
3782+
#endif
3783+
3784+
return ret;
3785+
}
3786+
37563787
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIORecv
37573788
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
37583789
{

native/com_wolfssl_WolfSSLSession.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/java/com/wolfssl/WolfSSL.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ public static enum TLS_VERSION {
186186
/** CertManager: disable sending OCSP nonce */
187187
public final static int WOLFSSL_OCSP_NO_NONCE = 2;
188188

189+
/* ALPN definitions from ssl.h */
190+
public final static int WOLFSSL_ALPN_NO_MATCH = 0;
191+
public final static int WOLFSSL_ALPN_MATCH = 1;
192+
public final static int WOLFSSL_ALPN_CONTINUE_ON_MISMATCH = 2;
193+
public final static int WOLFSSL_ALPN_FAILED_ON_MISMATCH = 4;
194+
189195
/* I/O callback default errors, pulled from wolfssl/ssl.h IOerrors */
190196
/** I/O callback error: general error */
191197
public final static int WOLFSSL_CBIO_ERR_GENERAL = -1;

src/java/com/wolfssl/WolfSSLSession.java

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.net.Socket;
2626
import java.net.DatagramSocket;
2727
import java.net.SocketTimeoutException;
28+
import java.lang.StringBuilder;
29+
import java.nio.charset.StandardCharsets;
2830

2931
import com.wolfssl.WolfSSLException;
3032
import com.wolfssl.WolfSSLJNIException;
@@ -276,6 +278,7 @@ private native int setTlsHmacInner(long ssl, byte[] inner, long sz,
276278
private native int gotCloseNotify(long ssl);
277279
private native int sslSetAlpnProtos(long ssl, byte[] alpnProtos);
278280
private native byte[] sslGet0AlpnSelected(long ssl);
281+
private native int useALPN(long ssl, String protocols, int options);
279282

280283
/* ------------------- session-specific methods --------------------- */
281284

@@ -2753,28 +2756,69 @@ public boolean sessionTicketsEnabled() throws IllegalStateException {
27532756
}
27542757

27552758
/**
2756-
* Set ALPN extension protocol for this session.
2757-
* Calls native SSL_set_alpn_protos() at native level. Format starts with
2759+
* Set ALPN extension protocol for this session from encoded byte array.
2760+
* Calls SSL_set_alpn_protos() at native level. Format starts with
27582761
* length, where length does not include length byte itself. Example format:
27592762
*
27602763
* byte[] p = "http/1.1".getBytes();
27612764
*
2765+
* Unless this input format is explicitly needed, useALPN(String[], int)
2766+
* will likely be easier to use.
2767+
*
27622768
* @param alpnProtos ALPN protocols, encoded as byte array vector
2763-
* @return WolfSSL.SSL_SUCCESS on success, otherwise negative.
2769+
* @return WolfSSL.SSL_SUCCESS on success, otherwise negative on error.
27642770
*/
2765-
public int setAlpnProtos(byte[] alpnProtos) throws IllegalStateException {
2771+
public int useALPN(byte[] alpnProtos) throws IllegalStateException {
27662772

27672773
if (this.active == false)
27682774
throw new IllegalStateException("Object has been freed");
27692775

27702776
return sslSetAlpnProtos(getSessionPtr(), alpnProtos);
27712777
}
27722778

2779+
/**
2780+
* Set ALPN extension protocol for this session from String array.
2781+
* Calls native wolfSSL_useALPN(), where protocols should be a String
2782+
* array of ALPN protocols. At the native JNI level, this is converted to
2783+
* a comma-delimited list of prototocls and passed to native wolfSSL.
2784+
*
2785+
* This method is similar to useALPN(byte[]), but accepts a String array
2786+
* and calls a different native wolfSSL API for ALPN use.
2787+
*
2788+
* @param protocols Array of ALPN protocol Strings
2789+
* @param options Options to control behavior of ALPN failure mode.
2790+
* Possible options include:
2791+
* WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH
2792+
* WolfSSL.WOLFSSL_ALPN_FAILED_ON_MISMATCH
2793+
* @return WolfSSL.SSL_SUCCESS on success, otherwise negative on error.
2794+
*
2795+
*/
2796+
public int useALPN(String[] protocols, int options) {
2797+
2798+
/* all protocols, comma delimited */
2799+
StringBuilder allProtocols = new StringBuilder();
2800+
2801+
if (this.active == false)
2802+
throw new IllegalStateException("Object has been freed");
2803+
2804+
if (protocols == null) {
2805+
return WolfSSL.BAD_FUNC_ARG;
2806+
}
2807+
2808+
for (int i = 0; i < protocols.length; i++) {
2809+
if (i != 0) {
2810+
allProtocols.append(",");
2811+
}
2812+
allProtocols.append(protocols[i]);
2813+
}
2814+
2815+
return useALPN(getSessionPtr(), allProtocols.toString(), options);
2816+
}
2817+
27732818
/**
27742819
* Get the ALPN protocol selected by the client/server for this session.
27752820
*
2776-
* @return byte array representation of selected protocol, starting with
2777-
* length byte. Length does not include length byte itself.
2821+
* @return byte array representation of selected protocol.
27782822
* @throws IllegalStateException WolfSSLSession has been freed
27792823
*/
27802824
public byte[] getAlpnSelected() throws IllegalStateException {
@@ -2785,6 +2829,23 @@ public byte[] getAlpnSelected() throws IllegalStateException {
27852829
return sslGet0AlpnSelected(getSessionPtr());
27862830
}
27872831

2832+
/**
2833+
* Get the ALPN protocol selected by the client/server for this session.
2834+
*
2835+
* Same behavior as getAlpnSelected(), but returns a String instead of a
2836+
* byte array.
2837+
*
2838+
* @return String of the selected ALPN protocol
2839+
* @throws IllegalStateException WolfSSLSession has been freed
2840+
*/
2841+
public String getAlpnSelectedString() throws IllegalStateException {
2842+
2843+
if (this.active == false)
2844+
throw new IllegalStateException("Object has been freed");
2845+
2846+
return new String(getAlpnSelected(), StandardCharsets.UTF_8);
2847+
}
2848+
27882849
/**
27892850
* Getter function to tell if shutdown has been sent or received
27902851
* @return WolfSSL.SSL_SENT_SHUTDOWN or WolfSSL.SSL_RECEIVED_SHUTDOWN

src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,10 @@ public boolean getEnableSessionCreation() {
545545
return EngineHelper.getEnableSessionCreation();
546546
}
547547

548+
public String getApplicationProtocol() {
549+
return EngineHelper.getAlpnSelectedProtocolString();
550+
}
551+
548552
/**
549553
* Set the SSLParameters for this SSLSocket.
550554
*

src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ protected void setAlpnProtocols(byte[] alpnProtos) {
358358
/**
359359
* Get selected ALPN protocol
360360
*
361+
* Used by some versions of Android, non-standard ALPN API.
362+
*
361363
* @return encoded byte array for selected ALPN protocol or null if
362364
* handshake has not finished
363365
*/
@@ -368,6 +370,18 @@ protected byte[] getAlpnSelectedProtocol() {
368370
return null;
369371
}
370372

373+
protected String getAlpnSelectedProtocolString() {
374+
if (ssl.handshakeDone()) {
375+
String proto = ssl.getAlpnSelectedString();
376+
377+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
378+
"selected ALPN protocol = " + proto);
379+
380+
return proto;
381+
}
382+
return null;
383+
}
384+
371385
/********** Calls to transfer over parameter to wolfSSL before connection */
372386

373387
/*transfer over cipher suites right before establishing a connection */
@@ -577,13 +591,51 @@ private void setLocalSessionTicket() {
577591

578592
/* Set the ALPN to be used for this session */
579593
private void setLocalAlpnProtocols() {
594+
595+
/* ALPN protocol list could be stored in either of the following,
596+
* depending on what platform/JDK we are being used on:
597+
* this.params.getAlpnProtos() or
598+
* this.params.getApplicationProtocols()
599+
* For example, Conscrypt consumers on older Android versions with
600+
* JDK 7 will be in params.getAlpnProtos(). JDK versions > 8, with
601+
* support for params.getApplicationProtocols() will likely use that
602+
* instead. */
603+
604+
int i;
580605
byte[] alpnProtos = this.params.getAlpnProtos();
606+
String[] applicationProtocols = this.params.getApplicationProtocols();
581607

582-
if (alpnProtos != null) {
608+
if ((alpnProtos != null && alpnProtos.length > 0) &&
609+
(applicationProtocols != null && applicationProtocols.length > 0)) {
583610
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
584-
"Setting ALPN protocols for WOLFSSL session");
585-
this.ssl.setAlpnProtos(alpnProtos);
586-
} else {
611+
"ALPN protocols found in both params.getAlpnProtos() and " +
612+
"params.getApplicationProtocols()");
613+
}
614+
615+
/* try to set from byte[] first, then overwrite with String[] if
616+
* both have been set */
617+
if (alpnProtos != null && alpnProtos.length > 0) {
618+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
619+
"Setting ALPN protocols for WOLFSSL session from byte[" +
620+
alpnProtos.length + "]");
621+
this.ssl.useALPN(alpnProtos);
622+
}
623+
624+
if (applicationProtocols != null && applicationProtocols.length > 0) {
625+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
626+
"Setting Application Protocols for WOLFSSL session " +
627+
"from String[]:");
628+
for (i = 0; i < applicationProtocols.length; i++) {
629+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
630+
"\t" + i + ": " + applicationProtocols[i]);
631+
}
632+
633+
/* continue on mismatch */
634+
this.ssl.useALPN(applicationProtocols,
635+
WolfSSL.WOLFSSL_ALPN_CONTINUE_ON_MISMATCH);
636+
}
637+
638+
if (alpnProtos == null && applicationProtocols == null) {
587639
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
588640
"No ALPN protocols set, not setting for this WOLFSSL session");
589641
}

src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public class WolfSSLParametersHelper
3333
{
3434
private static Method getServerNames = null;
3535
private static Method setServerNames = null;
36+
private static Method getApplicationProtocols = null;
37+
private static Method setApplicationProtocols = null;
3638

3739
/** Default WolfSSLParametersHelper constructor */
3840
public WolfSSLParametersHelper() { }
@@ -59,6 +61,12 @@ public Object run() {
5961
case "setServerNames":
6062
setServerNames = m;
6163
continue;
64+
case "getApplicationProtocols":
65+
getApplicationProtocols = m;
66+
continue;
67+
case "setApplicationProtocols":
68+
setApplicationProtocols = m;
69+
continue;
6270
default:
6371
continue;
6472
}
@@ -100,7 +108,7 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) {
100108
/* Methods added as of JDK 1.8, older JDKs will not have them. Using
101109
* Java reflection to detect availability. */
102110

103-
if (setServerNames != null) {
111+
if (setServerNames != null || setApplicationProtocols != null) {
104112

105113
try {
106114
/* load WolfSSLJDK8Helper at runtime, not compiled on older JDKs */
@@ -110,9 +118,16 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) {
110118
paramList[0] = javax.net.ssl.SSLParameters.class;
111119
paramList[1] = java.lang.reflect.Method.class;
112120
paramList[2] = com.wolfssl.provider.jsse.WolfSSLParameters.class;
121+
Method mth = null;
113122

114-
Method mth = cls.getDeclaredMethod("setServerNames", paramList);
115-
mth.invoke(obj, ret, setServerNames, in);
123+
if (setServerNames != null) {
124+
mth = cls.getDeclaredMethod("setServerNames", paramList);
125+
mth.invoke(obj, ret, setServerNames, in);
126+
}
127+
if (setApplicationProtocols != null) {
128+
mth = cls.getDeclaredMethod("setApplicationProtocols", paramList);
129+
mth.invoke(obj, ret, setServerNames, in);
130+
}
116131

117132
} catch (Exception e) {
118133
/* ignore, class not found */
@@ -124,7 +139,6 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) {
124139
* with newer versions of SSLParameters, but will need to be added
125140
* conditionally to wolfJSSE when supported. */
126141
/*ret.setAlgorithmConstraints(in.getAlgorithmConstraints());
127-
ret.setApplicationProtocols(in.getApplicationProtocols());
128142
ret.setEnableRetransmissions(in.getEnableRetransmissions());
129143
ret.setEndpointIdentificationAlgorithm(
130144
in.getEndpointIdentificationAlgorithm());
@@ -170,17 +184,24 @@ protected static void importParams(SSLParameters in,
170184
/* Methods added as of JDK 1.8, older JDKs will not have them. Using
171185
* Java reflection to detect availability. */
172186

173-
if (getServerNames != null) {
187+
if (getServerNames != null || getApplicationProtocols != null) {
174188
try {
175189
/* load WolfSSLJDK8Helper at runtime, not compiled on older JDKs */
176190
Class<?> cls = Class.forName("com.wolfssl.provider.jsse.WolfSSLJDK8Helper");
177191
Object obj = cls.getConstructor().newInstance();
178192
Class[] paramList = new Class[2];
179193
paramList[0] = javax.net.ssl.SSLParameters.class;
180194
paramList[1] = com.wolfssl.provider.jsse.WolfSSLParameters.class;
195+
Method mth = null;
181196

182-
Method mth = cls.getDeclaredMethod("getServerNames", paramList);
183-
mth.invoke(obj, in, out);
197+
if (getServerNames != null) {
198+
mth = cls.getDeclaredMethod("getServerNames", paramList);
199+
mth.invoke(obj, in, out);
200+
}
201+
if (getApplicationProtocols != null) {
202+
mth = cls.getDeclaredMethod("getApplicationProtocols", paramList);
203+
mth.invoke(obj, in, out);
204+
}
184205

185206
} catch (Exception e) {
186207
/* ignore, class not found */
@@ -192,7 +213,6 @@ protected static void importParams(SSLParameters in,
192213
* with newer versions of SSLParameters, but will need to be added
193214
* conditionally to wolfJSSE when supported. */
194215
/*out.setAlgorithmConstraints(in.getAlgorithmConstraints());
195-
out.setApplicationProtocols(in.getApplicationProtocols());
196216
out.setEnableRetransmissions(in.getEnableRetransmissions());
197217
out.setEndpointIdentificationAlgorithm(
198218
in.getEndpointIdentificationAlgorithm());

0 commit comments

Comments
 (0)