Skip to content

Commit 3dfbaa1

Browse files
committed
move peek logic higher in unwrap, do not consume data if
BUFFER_UNDERFLOW encountered edit comment
1 parent 9b08e4b commit 3dfbaa1

1 file changed

Lines changed: 156 additions & 110 deletions

File tree

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

Lines changed: 156 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,10 +1459,46 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP &&
14591459
prevSessionTicketCount = this.sessionTicketCount;
14601460
}
14611461

1462+
boolean hsUnderflow = false;
14621463
if (this.handshakeFinished == false) {
1463-
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1464-
() -> "starting or continuing handshake");
1465-
ret = DoHandshake(false);
1464+
/* Client mode: pre-check record header to return
1465+
* BUFFER_UNDERFLOW with bytesConsumed == 0 per
1466+
* the JSSE spec. Bogus headers fall through to
1467+
* wolfSSL. Server mode is excluded: wolfSSL buffers
1468+
* partial records via the I/O callback and returns
1469+
* WANT_READ, mapping to OK + NEED_UNWRAP. Returning
1470+
* BUFFER_UNDERFLOW server-side would break the
1471+
* SSLEngineExplorer pattern, whose BUFFER_UNDERFLOW
1472+
* handler reads from the socket, not the pre-read
1473+
* ClientHello buffer. */
1474+
if (this.getUseClientMode() &&
1475+
inRemaining > 0 &&
1476+
(this.ssl.dtls() == 0)) {
1477+
synchronized (netDataLock) {
1478+
int pos = in.position();
1479+
if (inRemaining < TLS_RECORD_HEADER_LEN) {
1480+
hsUnderflow = true;
1481+
} else {
1482+
int recLen =
1483+
((in.get(pos + TLS_RECORD_LEN_HI_OFF)
1484+
& 0xFF) << 8) |
1485+
(in.get(pos + TLS_RECORD_LEN_LO_OFF)
1486+
& 0xFF);
1487+
if (recLen <= WolfSSL.MAX_RECORD_SIZE
1488+
&& inRemaining <
1489+
TLS_RECORD_HEADER_LEN + recLen) {
1490+
hsUnderflow = true;
1491+
}
1492+
}
1493+
}
1494+
}
1495+
if (hsUnderflow) {
1496+
status = SSLEngineResult.Status.BUFFER_UNDERFLOW;
1497+
} else {
1498+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1499+
() -> "starting or continuing handshake");
1500+
ret = DoHandshake(false);
1501+
}
14661502
}
14671503
else {
14681504
/* TLS-only: peek at the record header and
@@ -1488,8 +1524,9 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP &&
14881524
& 0xFF) << 8) |
14891525
(in.get(pos + TLS_RECORD_LEN_LO_OFF)
14901526
& 0xFF);
1491-
if (inRemaining <
1492-
TLS_RECORD_HEADER_LEN + recLen) {
1527+
if (recLen <= WolfSSL.MAX_RECORD_SIZE
1528+
&& inRemaining <
1529+
TLS_RECORD_HEADER_LEN + recLen) {
14931530
bufferUnderflow = true;
14941531
}
14951532
}
@@ -1527,11 +1564,13 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP &&
15271564
}
15281565
else {
15291566
/* Still not enough output space */
1530-
status = SSLEngineResult.Status.BUFFER_OVERFLOW;
1567+
status =
1568+
SSLEngineResult.Status.BUFFER_OVERFLOW;
15311569
}
15321570
}
15331571
else if (bufferUnderflow) {
1534-
status = SSLEngineResult.Status.BUFFER_UNDERFLOW;
1572+
status =
1573+
SSLEngineResult.Status.BUFFER_UNDERFLOW;
15351574
}
15361575
/* If we have input data, make sure output buffer
15371576
* length is greater than zero, otherwise ask app to
@@ -1616,7 +1655,8 @@ else if (inRemaining > 0 &&
16161655
(ssl.getError(0) == 0) &&
16171656
!this.sessionStored) {
16181657
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1619-
() -> "calling engineHelper.saveSession()");
1658+
() ->
1659+
"calling engineHelper.saveSession()");
16201660
int ret2 = this.engineHelper.saveSession();
16211661
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
16221662
() -> "return from saveSession(), ret = " +
@@ -1628,123 +1668,129 @@ else if (inRemaining > 0 &&
16281668
}
16291669
} /* end DoHandshake() / RecvAppData() */
16301670

1631-
if (outBoundOpen == false || this.closeNotifySent ||
1632-
this.closeNotifyReceived) {
1633-
/* Mark SSLEngine status as CLOSED */
1634-
status = SSLEngineResult.Status.CLOSED;
1635-
/* Handshake has finished and SSLEngine is closed,
1636-
* release, global JNI verify callback pointer */
1637-
this.engineHelper.unsetVerifyCallback();
1638-
}
1671+
if (!hsUnderflow) {
1672+
if (outBoundOpen == false || this.closeNotifySent ||
1673+
this.closeNotifyReceived) {
1674+
/* Mark SSLEngine status as CLOSED */
1675+
status = SSLEngineResult.Status.CLOSED;
1676+
/* Handshake has finished and SSLEngine is closed,
1677+
* release, global JNI verify callback pointer */
1678+
this.engineHelper.unsetVerifyCallback();
1679+
}
16391680

1640-
synchronized (ioLock) {
1641-
err = ssl.getError(ret);
1642-
}
1643-
if (ret < 0 && (this.ssl.dtls() == 1) &&
1644-
(err == WolfSSL.OUT_OF_ORDER_E)) {
1645-
/* Received out of order DTLS message. Ignore and set
1646-
* our status to NEED_UNWRAP again to wait for correct
1647-
* data */
1648-
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1649-
() -> "out of order message, dropping and " +
1650-
"putting state back to NEED_UNWRAP");
1651-
}
1652-
else if (ret < 0 &&
1653-
(err != WolfSSL.SSL_ERROR_WANT_READ) &&
1654-
(err != WolfSSL.SSL_ERROR_WANT_WRITE)) {
1655-
1656-
if (err == WolfSSL.UNKNOWN_ALPN_PROTOCOL_NAME_E) {
1657-
/* Native wolfSSL could not negotiate a common ALPN
1658-
* protocol */
1659-
this.inBoundOpen = false;
1660-
throw new SSLHandshakeException(
1661-
"Unrecognized protocol name error, ret:err = " +
1662-
ret + " : " + err);
1681+
synchronized (ioLock) {
1682+
err = ssl.getError(ret);
16631683
}
1664-
else {
1665-
/* Native wolfSSL threw an exception when unwrapping
1666-
* data, close inbound since we can't receive more
1667-
* data */
1668-
this.inBoundOpen = false;
1669-
if (err == WolfSSL.FATAL_ERROR) {
1670-
/* If client side and we received fatal alert,
1671-
* close outbound since we won't be receiving
1672-
* any more data */
1673-
this.outBoundOpen = false;
1674-
}
1675-
/* Throw SSLHandshakeException if handshake not
1676-
* finished, otherwise throw SSLException for
1677-
* post-handshake errors */
1678-
if (!this.handshakeFinished) {
1679-
SSLHandshakeException hse2 =
1680-
new SSLHandshakeException(
1681-
"SSL/TLS handshake error, ret:err = " +
1684+
if (ret < 0 && (this.ssl.dtls() == 1) &&
1685+
(err == WolfSSL.OUT_OF_ORDER_E)) {
1686+
/* Received out of order DTLS message. Ignore and
1687+
* set our status to NEED_UNWRAP again to wait for
1688+
* correct data */
1689+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
1690+
() -> "out of order message, dropping and " +
1691+
"putting state back to NEED_UNWRAP");
1692+
}
1693+
else if (ret < 0 &&
1694+
(err != WolfSSL.SSL_ERROR_WANT_READ) &&
1695+
(err != WolfSSL.SSL_ERROR_WANT_WRITE)) {
1696+
1697+
if (err == WolfSSL.UNKNOWN_ALPN_PROTOCOL_NAME_E) {
1698+
/* Native wolfSSL could not negotiate a common
1699+
* ALPN protocol */
1700+
this.inBoundOpen = false;
1701+
throw new SSLHandshakeException(
1702+
"Unrecognized protocol name error, ret:err = " +
16821703
ret + " : " + err);
1683-
if (this.engineHelper != null) {
1684-
Exception verifyEx2 = this.engineHelper
1685-
.getLastVerifyException();
1686-
if (verifyEx2 != null) {
1687-
hse2.initCause(verifyEx2);
1704+
}
1705+
else {
1706+
/* Native wolfSSL threw an exception when
1707+
* unwrapping data, close inbound since we
1708+
* can't receive more data */
1709+
this.inBoundOpen = false;
1710+
if (err == WolfSSL.FATAL_ERROR) {
1711+
/* If client side and we received fatal
1712+
* alert, close outbound since we won't be
1713+
* receiving any more data */
1714+
this.outBoundOpen = false;
1715+
}
1716+
/* Throw SSLHandshakeException if handshake not
1717+
* finished, otherwise throw SSLException for
1718+
* post-handshake errors */
1719+
if (!this.handshakeFinished) {
1720+
SSLHandshakeException hse2 =
1721+
new SSLHandshakeException(
1722+
"SSL/TLS handshake error, ret:err = " +
1723+
ret + " : " + err);
1724+
if (this.engineHelper != null) {
1725+
Exception verifyEx2 = this.engineHelper
1726+
.getLastVerifyException();
1727+
if (verifyEx2 != null) {
1728+
hse2.initCause(verifyEx2);
1729+
}
16881730
}
1731+
throw hse2;
16891732
}
1690-
throw hse2;
1733+
throw new SSLException(
1734+
"wolfSSL error, ret:err = " + ret + " : " +
1735+
err);
16911736
}
1692-
throw new SSLException(
1693-
"wolfSSL error, ret:err = " + ret + " : " +
1694-
err);
16951737
}
1696-
}
1697-
else if (!this.handshakeFinished && (ret == 0) &&
1698-
(err == 0 || err == WolfSSL.SSL_ERROR_ZERO_RETURN)) {
1738+
else if (!this.handshakeFinished && (ret == 0) &&
1739+
(err == 0 ||
1740+
err == WolfSSL.SSL_ERROR_ZERO_RETURN)) {
16991741

1700-
boolean gotCloseNotify = false;
1701-
synchronized (ioLock) {
1702-
gotCloseNotify = this.ssl.gotCloseNotify();
1703-
}
1742+
boolean gotCloseNotify = false;
1743+
synchronized (ioLock) {
1744+
gotCloseNotify = this.ssl.gotCloseNotify();
1745+
}
17041746

1705-
if (!gotCloseNotify && !this.closeNotifyReceived) {
1706-
this.inBoundOpen = false;
1707-
this.outBoundOpen = false;
1708-
throw new SSLHandshakeException(
1709-
"Peer closed connection during handshake");
1747+
if (!gotCloseNotify && !this.closeNotifyReceived) {
1748+
this.inBoundOpen = false;
1749+
this.outBoundOpen = false;
1750+
throw new SSLHandshakeException(
1751+
"Peer closed connection during handshake");
1752+
}
17101753
}
1711-
}
17121754

1713-
/* Get DTLS drop count after data has been processed. To be
1714-
* used below when setting BUFFER_UNDERFLOW status. */
1715-
synchronized (ioLock) {
1716-
dtlsCurrDropCount = ssl.getDtlsMacDropCount();
1717-
}
1755+
/* Get DTLS drop count after data has been processed.
1756+
* To be used below when setting BUFFER_UNDERFLOW
1757+
* status. */
1758+
synchronized (ioLock) {
1759+
dtlsCurrDropCount = ssl.getDtlsMacDropCount();
1760+
}
17181761

1719-
/* Detect if we need to set BUFFER_UNDERFLOW.
1720-
* If we consume data in unwrap() but it's just a session
1721-
* ticket, we don't set BUFFER_UNDERFLOW and just continue
1722-
* on to set status as OK. */
1723-
synchronized (toSendLock) {
1724-
synchronized (netDataLock) {
1725-
if (ret <= 0 &&
1726-
err == WolfSSL.SSL_ERROR_WANT_READ &&
1727-
in.remaining() == 0 &&
1728-
inRemaining == 0 &&
1729-
(this.internalIOSendBufOffset == 0) &&
1730-
(prevSessionTicketCount ==
1731-
this.sessionTicketCount)) {
1732-
1733-
if ((this.ssl.dtls() == 0) ||
1734-
(this.handshakeFinished &&
1735-
(dtlsPrevDropCount ==
1736-
dtlsCurrDropCount))) {
1737-
/* Need more data. For DTLS only set
1738-
* after handshake has completed, since
1739-
* apps expect to switch on NEED_UNWRAP
1740-
* HandshakeStatus at that point */
1741-
status =
1742-
SSLEngineResult.Status.BUFFER_UNDERFLOW;
1762+
/* Detect if we need to set BUFFER_UNDERFLOW.
1763+
* If we consume data in unwrap() but it's just a
1764+
* session ticket, we don't set BUFFER_UNDERFLOW and
1765+
* just continue on to set status as OK. */
1766+
synchronized (toSendLock) {
1767+
synchronized (netDataLock) {
1768+
if (ret <= 0 &&
1769+
err == WolfSSL.SSL_ERROR_WANT_READ &&
1770+
in.remaining() == 0 &&
1771+
inRemaining == 0 &&
1772+
(this.internalIOSendBufOffset == 0) &&
1773+
(prevSessionTicketCount ==
1774+
this.sessionTicketCount)) {
1775+
1776+
if ((this.ssl.dtls() == 0) ||
1777+
(this.handshakeFinished &&
1778+
(dtlsPrevDropCount ==
1779+
dtlsCurrDropCount))) {
1780+
/* Need more data. For DTLS only set
1781+
* after handshake has completed, since
1782+
* apps expect to switch on NEED_UNWRAP
1783+
* HandshakeStatus at that point */
1784+
status =
1785+
SSLEngineResult.Status
1786+
.BUFFER_UNDERFLOW;
1787+
}
17431788
}
17441789
}
17451790
}
1746-
}
1747-
}
1791+
} /* end if (!hsUnderflow) */
1792+
1793+
} /* end else (outBoundOpen == true) */
17481794

17491795
synchronized (netDataLock) {
17501796
consumed += in.position() - inPosition;

0 commit comments

Comments
 (0)