@@ -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