Skip to content

Commit 7bb4cfa

Browse files
Merge pull request #84 from cconlon/sslEngineAlpn
Add support for SSLEngine.getApplicationProtocol()
2 parents 59afb97 + 751ca6e commit 7bb4cfa

10 files changed

Lines changed: 348 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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ 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+
/** ALPN: no match found */
191+
public final static int WOLFSSL_ALPN_NO_MATCH = 0;
192+
/** ALPN: found match */
193+
public final static int WOLFSSL_ALPN_MATCH = 1;
194+
/** ALPN: continue on protocol mismatch */
195+
public final static int WOLFSSL_ALPN_CONTINUE_ON_MISMATCH = 2;
196+
/** ALPN: failed on protocol mismatch */
197+
public final static int WOLFSSL_ALPN_FAILED_ON_MISMATCH = 4;
198+
189199
/* I/O callback default errors, pulled from wolfssl/ssl.h IOerrors */
190200
/** I/O callback error: general error */
191201
public final static int WOLFSSL_CBIO_ERR_GENERAL = -1;

src/java/com/wolfssl/WolfSSLSession.java

Lines changed: 75 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,31 @@ 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+
byte[] alpnSelectedBytes = null;
2844+
2845+
if (this.active == false)
2846+
throw new IllegalStateException("Object has been freed");
2847+
2848+
alpnSelectedBytes = getAlpnSelected();
2849+
2850+
if (alpnSelectedBytes != null) {
2851+
return new String(alpnSelectedBytes, StandardCharsets.UTF_8);
2852+
} else {
2853+
return null;
2854+
}
2855+
}
2856+
27882857
/**
27892858
* Getter function to tell if shutdown has been sent or received
27902859
* @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: 62 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,24 @@ protected byte[] getAlpnSelectedProtocol() {
368370
return null;
369371
}
370372

373+
/**
374+
* Get selected ALPN protocol string
375+
*
376+
* @return String representation of selected ALPN protocol or null
377+
* if handshake has not finished
378+
*/
379+
protected String getAlpnSelectedProtocolString() {
380+
if (ssl.handshakeDone()) {
381+
String proto = ssl.getAlpnSelectedString();
382+
383+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
384+
"selected ALPN protocol = " + proto);
385+
386+
return proto;
387+
}
388+
return null;
389+
}
390+
371391
/********** Calls to transfer over parameter to wolfSSL before connection */
372392

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

578598
/* Set the ALPN to be used for this session */
579599
private void setLocalAlpnProtocols() {
600+
601+
/* ALPN protocol list could be stored in either of the following,
602+
* depending on what platform/JDK we are being used on:
603+
* this.params.getAlpnProtos() or
604+
* this.params.getApplicationProtocols()
605+
* For example, Conscrypt consumers on older Android versions with
606+
* JDK 7 will be in params.getAlpnProtos(). JDK versions > 8, with
607+
* support for params.getApplicationProtocols() will likely use that
608+
* instead. */
609+
610+
int i;
580611
byte[] alpnProtos = this.params.getAlpnProtos();
612+
String[] applicationProtocols = this.params.getApplicationProtocols();
581613

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

0 commit comments

Comments
 (0)