Skip to content

Commit 43d6b42

Browse files
authored
Merge pull request #363 from cconlon/scanIssues
Security and correctness fixes from internal scan
2 parents 57f35cf + 7addc50 commit 43d6b42

5 files changed

Lines changed: 133 additions & 66 deletions

File tree

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ private void initKeyManager(KeyManager[] in)
145145
if (managers[i] instanceof X509KeyManager) {
146146
km = (X509KeyManager)managers[i];
147147
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
148-
() -> "located X509KeyManager instance: " + km);
148+
() -> "located X509KeyManager instance: " +
149+
km.getClass().getName());
149150
break;
150151
}
151152
}
@@ -185,7 +186,8 @@ private void initTrustManager(TrustManager[] in)
185186
if (managers[i] instanceof X509TrustManager) {
186187
tm = (X509TrustManager)managers[i];
187188
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
188-
() -> "located X509TrustManager instance: " + tm);
189+
() -> "located X509TrustManager instance: " +
190+
tm.getClass().getName());
189191
break;
190192
}
191193
}
@@ -201,8 +203,9 @@ private void initSecureRandom(SecureRandom random) {
201203

202204
if (random == null) {
203205
sr = new SecureRandom();
206+
} else {
207+
sr = random;
204208
}
205-
sr = random;
206209
}
207210

208211
/**
@@ -616,6 +619,7 @@ protected int addSession(WolfSSLImplementSSLSession session) {
616619

617620
String toHash;
618621
final int hashCode;
622+
final boolean haveKey;
619623

620624
/* Don't store session if invalid (or not complete with sesPtr
621625
* if on client side, or not resumable). Server-side still needs to
@@ -639,6 +643,7 @@ protected int addSession(WolfSSLImplementSSLSession session) {
639643
toHash = session.getPeerHost().concat(Integer.toString(
640644
session.getPeerPort()));
641645
hashCode = toHash.hashCode();
646+
haveKey = true;
642647
}
643648
else {
644649
/* If no peer host is available then create hash key from
@@ -647,15 +652,18 @@ protected int addSession(WolfSSLImplementSSLSession session) {
647652
if (sessionId != null && sessionId.length > 0 &&
648653
(idAllZeros(sessionId) == false)) {
649654
hashCode = Arrays.toString(session.getId()).hashCode();
655+
haveKey = true;
650656
} else {
651657
hashCode = 0;
658+
haveKey = false;
652659
}
653660
}
654661

655-
/* Always try to store session into cache table, as long as we
656-
* have a hashCode. If session already exists for hashCode, it
657-
* will be overwritten with new/refreshed version */
658-
if (hashCode != 0) {
662+
/* Only store session into cache if we have a usable key. If session
663+
* already exists for hashCode, it will be overwritten with the new
664+
* version. Note that hashCode == 0 is a legitimate hash value, so
665+
* we use haveKey rather than hashCode == 0 to gate caching. */
666+
if (haveKey) {
659667
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
660668
() -> "stored session in cache table (host: " +
661669
session.getPeerHost() + ", port: " +
@@ -669,8 +677,12 @@ protected int addSession(WolfSSLImplementSSLSession session) {
669677
}
670678

671679
printSessionStoreStatus();
680+
return WolfSSL.SSL_SUCCESS;
672681
}
673682

683+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
684+
() -> "Session not cached: no peer host and no usable session ID");
685+
674686
return WolfSSL.SSL_SUCCESS;
675687
}
676688

@@ -746,11 +758,13 @@ protected void updateTimeouts(int in, int side) {
746758
diff = (now - current.creation.getTime()) / 1000;
747759

748760
if (diff < 0) {
749-
/* session is from the future ... */ /* TODO */
750-
761+
/* Session creation time in the future. Invalidate so
762+
* it cannot persist indefinitely past the timeout. */
763+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
764+
() -> "Invalidating session with future creation");
765+
current.invalidate();
751766
}
752-
753-
if (in > 0 && diff >= in) {
767+
else if (in > 0 && diff >= in) {
754768
current.invalidate();
755769
}
756770
try {

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.security.cert.CertificateEncodingException;
2727
import java.security.cert.X509Certificate;
2828
import javax.security.auth.x500.X500Principal;
29-
import java.util.Arrays;
3029

3130
import javax.net.ssl.KeyManager;
3231
import javax.net.ssl.SSLContextSpi;
@@ -310,7 +309,7 @@ private void LoadTrustedRootCerts() {
310309
}
311310

312311
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
313-
() -> "Using X509TrustManager: " + tm.toString());
312+
() -> "Using X509TrustManager: " + tm.getClass().getName());
314313

315314
/* We only need to load trusted CA certificates into our native
316315
* WOLFSSL_CTX if we are doing internal verification with wolfSSL
@@ -364,10 +363,12 @@ private void LoadTrustedRootCerts() {
364363
/* skip loading if encoding error is encountered */
365364
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
366365
() -> "skipped loading CA, encoding error");
366+
continue;
367367
} catch (WolfSSLJNIException we) {
368368
/* skip loading if wolfSSL fails to load der encoding */
369369
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
370370
() -> "skipped loading CA, JNI exception");
371+
continue;
371372
}
372373

373374
final String sigAltName = caList[i].getSigAlgName();
@@ -385,6 +386,24 @@ private void LoadTrustedRootCerts() {
385386
}
386387
}
387388

389+
/* Format an array of objects as "[Class1, Class2, ...]" for debug
390+
* logging without invoking caller-supplied toString() on user-provided
391+
* KeyManager/TrustManager objects. */
392+
private static String classNames(Object[] arr) {
393+
if (arr == null) {
394+
return "null";
395+
}
396+
StringBuilder sb = new StringBuilder("[");
397+
for (int i = 0; i < arr.length; i++) {
398+
if (i > 0) {
399+
sb.append(", ");
400+
}
401+
sb.append(arr[i] == null ? "null" : arr[i].getClass().getName());
402+
}
403+
sb.append("]");
404+
return sb.toString();
405+
}
406+
388407
/**
389408
* Initializes a SSLContext.
390409
*
@@ -406,8 +425,9 @@ protected void engineInit(KeyManager[] km, TrustManager[] tm,
406425
SecureRandom sr) throws KeyManagementException {
407426

408427
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
409-
() -> "entered engineInit(km=" + Arrays.toString(km) + ", tm=" +
410-
Arrays.toString(tm) + ", sr=" + sr +")");
428+
() -> "entered engineInit(km=" + classNames(km) + ", tm=" +
429+
classNames(tm) + ", sr=" +
430+
(sr == null ? "null" : sr.getClass().getName()) + ")");
411431

412432
try {
413433
authStore = new WolfSSLAuthStore(km, tm, sr, currentVersion,
@@ -620,7 +640,7 @@ protected void finalize() throws Throwable {
620640
* @return String array of enabled SSL/TLS protocols for this
621641
* WolfSSLContext object
622642
*/
623-
public String[] getProtocolsMask(long noOpt) {
643+
private String[] getProtocolsMask(long noOpt) {
624644
if (ctx != null) {
625645
ctx.setOptions(noOpt);
626646
}

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

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ public class WolfSSLEngine extends SSLEngine {
134134
* inside SendAppData, of size SSLSession.getApplicationBufferSize() */
135135
private ByteBuffer staticAppDataBuf = null;
136136

137+
/* Largest plaintext byte count written into staticAppDataBuf by the most
138+
* recent SendAppData() call. Used to bound the post-write zeroing range
139+
* so residual plaintext from a prior larger write is wiped even when the
140+
* current write is smaller. Bytes past max(sendSz, lastSendSz) never need
141+
* zeroing here: ByteBuffer.allocateDirect() zero-initializes the buffer,
142+
* and SendAppData() is the only writer of plaintext into it. */
143+
private int lastSendSz = 0;
144+
137145
/* Stashed decrypted data when output buffer too small.
138146
* Served on next unwrap() without calling ssl_read(). */
139147
private byte[] pendingAppData = null;
@@ -780,14 +788,31 @@ private synchronized int SendAppData(ByteBuffer[] in, int ofst, int len)
780788
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
781789
() -> "calling ssl.write() with size: " + tmpSendSz);
782790

783-
synchronized (ioLock) {
784-
ret = this.ssl.write(dataArr, sendSz);
785-
}
786-
if (ret <= 0) {
787-
/* error, reset in[] positions for next call */
788-
for (i = ofst; i < ofst + len; i++) {
789-
in[i].position(pos[i - ofst]);
791+
try {
792+
synchronized (ioLock) {
793+
ret = this.ssl.write(dataArr, sendSz);
790794
}
795+
if (ret <= 0) {
796+
/* error, reset in[] positions for next call */
797+
for (i = ofst; i < ofst + len; i++) {
798+
in[i].position(pos[i - ofst]);
799+
}
800+
}
801+
} finally {
802+
/* Zero plaintext from heap and direct buffers even on exception.
803+
* Zero up to max(sendSz, lastSendSz) bytes so bytes from a prior
804+
* larger write are wiped if needed. */
805+
Arrays.fill(dataArr, (byte)0);
806+
int zeroSz = Math.max(sendSz, this.lastSendSz);
807+
/* clear() resets position/limit only, does not zero bytes */
808+
this.staticAppDataBuf.clear();
809+
/* Bulk put faster than a per-byte loop on DirectByteBuffer */
810+
this.staticAppDataBuf.put(dataArr, 0, sendSz);
811+
/* Loop wipes [sendSz, lastSendSz) when previous write was larger */
812+
for (int j = sendSz; j < zeroSz; j++) {
813+
this.staticAppDataBuf.put((byte)0);
814+
}
815+
this.lastSendSz = sendSz;
791816
}
792817

793818
final int tmpRet = ret;
@@ -1077,17 +1102,19 @@ else if (produced == 0) {
10771102
* @return number of available/remaining bytes in array of ByteBuffers
10781103
* @throws IllegalArgumentException if readonly buffer found
10791104
*/
1080-
private static synchronized int getTotalOutputSize(ByteBuffer[] out,
1081-
int ofst, int length) {
1105+
private static int getTotalOutputSize(ByteBuffer[] out,
1106+
int ofst, int length) {
1107+
10821108
int i = 0;
10831109
int maxOutSz = 0;
10841110

10851111
for (i = 0; i < length; i++) {
1086-
if (out[i + ofst] == null || out[i + ofst].isReadOnly()) {
1112+
ByteBuffer buf = out[i + ofst];
1113+
if (buf == null || buf.isReadOnly()) {
10871114
throw new IllegalArgumentException(
10881115
"null or readonly out buffer found");
10891116
}
1090-
maxOutSz += out[i + ofst].remaining();
1117+
maxOutSz += buf.remaining();
10911118
}
10921119

10931120
return maxOutSz;
@@ -2301,7 +2328,9 @@ else if (!this.needInit && !this.handshakeFinished) {
23012328
this.handshakeStartedExplicitly = true;
23022329

23032330
} catch (SocketTimeoutException e) {
2304-
e.printStackTrace();
2331+
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
2332+
() -> "doHandshake() timed out in beginHandshake(): " +
2333+
e.getMessage());
23052334
throw new SSLException(e);
23062335

23072336
} finally {
@@ -2813,11 +2842,16 @@ protected synchronized void finalize() throws Throwable {
28132842
this.ssl.freeSSL();
28142843
this.ssl = null;
28152844
}
2816-
/* Clear our reference to static application direct ByteBuffer */
2845+
/* Zero only the byte range that held plaintext and drop our reference
2846+
* to the buffer. */
28172847
if (this.staticAppDataBuf != null) {
28182848
this.staticAppDataBuf.clear();
2849+
for (int j = 0; j < this.lastSendSz; j++) {
2850+
this.staticAppDataBuf.put((byte)0);
2851+
}
28192852
this.staticAppDataBuf = null;
28202853
}
2854+
this.lastSendSz = 0;
28212855
super.finalize();
28222856
}
28232857
}

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ protected synchronized Exception getLastVerifyException() {
516516
*
517517
* @return String array of all supported cipher suites
518518
*/
519-
protected static synchronized String[] getAllCiphers() {
519+
protected static String[] getAllCiphers() {
520520
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), false);
521521
}
522522

@@ -638,7 +638,7 @@ protected synchronized String[] getProtocols() {
638638
*
639639
* @return String array of supported protocols
640640
*/
641-
protected static synchronized String[] getAllProtocols() {
641+
protected static String[] getAllProtocols() {
642642
return WolfSSLUtil.sanitizeProtocols(
643643
WolfSSL.getProtocols(), WolfSSL.TLS_VERSION.INVALID);
644644
}
@@ -1696,7 +1696,7 @@ protected synchronized int doHandshake(int isSSLEngine, int timeout)
16961696
/* send CloseNotify */
16971697
/* TODO: SunJSSE sends a Handshake Failure alert instead here */
16981698
this.ssl.shutdownSSL();
1699-
} catch (SocketException e) {
1699+
} catch (SocketException | SocketTimeoutException e) {
17001700
throw new SSLException(e);
17011701
}
17021702

@@ -1712,6 +1712,13 @@ protected synchronized int doHandshake(int isSSLEngine, int timeout)
17121712
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
17131713
() -> "session creation not allowed");
17141714

1715+
try {
1716+
/* send CloseNotify so peer is not left hanging */
1717+
this.ssl.shutdownSSL();
1718+
} catch (SocketException | SocketTimeoutException e) {
1719+
throw new SSLException(e);
1720+
}
1721+
17151722
return WolfSSL.SSL_HANDSHAKE_FAILURE;
17161723
}
17171724

0 commit comments

Comments
 (0)