/* Caller is indicating 'bytes' of data was written */ int32 matrixSslSentData(ssl_t *ssl, uint32 bytes) { int32 rc; if (!ssl) { return PS_ARG_FAIL; } if (bytes == 0) { if (ssl->outlen > 0) { return MATRIXSSL_REQUEST_SEND; } else { return MATRIXSSL_SUCCESS; /* Nothing to do */ } } psAssert(ssl->outsize > 0 && ssl->outbuf != NULL); ssl->outlen -= bytes; rc = MATRIXSSL_SUCCESS; if (ssl->outlen > 0) { memmove(ssl->outbuf, ssl->outbuf + bytes, ssl->outlen); /* This was changed during 3.7.1 DTLS work. The line below used to be: rc = MATRIXSSL_REQUEST_SEND; and it was possible for it to be overridden with HANDSHAKE_COMPLETE below. This was a problem if only the ChangeCipherSpec portion of the final flight was just set becuase matrixSslHandshakeIsComplete would return 1 because the state looks right. However, there would still be a FINISHED message sitting in outbuf when COMPLETE is returned. This seemed like a bigger problem than just the DTLS test case that caught it. If the transport layer of straight TLS sent off only the CCS message for some reason, this would cause the same odd combo of COMPLETE but with a FINISHED message that hasn't been sent. It seems fine to return REQUEST_SEND whenever there is data left in the outgoing buffer but it is suspecious it wasn't written this way to begin with so maybe there was another corner case the COMPLETE was solving. Hope not. In any case, it looks safe to make this a global change but if you are reading this because you are trying to track down a change in behavior in matrixSslSentData, maybe this documentation will help. */ return MATRIXSSL_REQUEST_SEND; } /* If there's nothing left to flush, reallocate the buffer smaller. */ if ((ssl->outlen == 0) && (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT)) { /* We want to close the connection now */ rc = MATRIXSSL_REQUEST_CLOSE; } else { revertToDefaultBufsize(ssl, SSL_OUTBUF); } /* Indicate the handshake is complete, in this case, the finished message is being/has been just sent. Occurs in session resumption. */ if (!(ssl->bFlags & BFLAG_HS_COMPLETE) && matrixSslHandshakeIsComplete(ssl)) { ssl->bFlags |= BFLAG_HS_COMPLETE; #ifdef USE_CLIENT_SIDE_SSL matrixSslGetSessionId(ssl, ssl->sid); #endif /* USE_CLIENT_SIDE_SSL */ rc = MATRIXSSL_HANDSHAKE_COMPLETE; #ifdef USE_SSL_INFORMATIONAL_TRACE /* Client side resumed completion or server standard completion */ matrixSslPrintHSDetails(ssl); #endif } return rc; }
/* Caller is indicating 'bytes' of data was written */ int32 matrixSslSentData(ssl_t *ssl, uint32 bytes) { int32 rc; if (!ssl) { return PS_ARG_FAIL; } if (bytes == 0) { if (ssl->outlen > 0) { return MATRIXSSL_REQUEST_SEND; } else { return MATRIXSSL_SUCCESS; /* Nothing to do */ } } psAssert(ssl->outsize > 0 && ssl->outbuf != NULL); ssl->outlen -= bytes; rc = MATRIXSSL_SUCCESS; if (ssl->outlen > 0) { memmove(ssl->outbuf, ssl->outbuf + bytes, ssl->outlen); rc = MATRIXSSL_REQUEST_SEND; } /* If there's nothing left to flush, reallocate the buffer smaller. */ if ((ssl->outlen == 0) && (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT)) { /* We want to close the connection now */ rc = MATRIXSSL_REQUEST_CLOSE; } else { revertToDefaultBufsize(ssl, SSL_OUTBUF); } /* Indicate the handshake is complete, in this case, the finished message is being/has been just sent. Occurs in session resumption. */ if (!(ssl->bFlags & BFLAG_HS_COMPLETE) && matrixSslHandshakeIsComplete(ssl)) { ssl->bFlags |= BFLAG_HS_COMPLETE; #ifdef USE_CLIENT_SIDE_SSL matrixSslGetSessionId(ssl, ssl->sid); #endif /* USE_CLIENT_SIDE_SSL */ rc = MATRIXSSL_HANDSHAKE_COMPLETE; #ifdef USE_SSL_INFORMATIONAL_TRACE /* Client side resumed completion or server standard completion */ matrixSslPrintHSDetails(ssl); #endif #ifdef USE_UNIFIED_PKCS11 /* Too ugly to track DTLS client/server/normal/resumed/rehandshake cases for deleting old crypto session objects for the minimum lifecycle so we're just looking for any leftover cases here when we are certain handshake is complete. NOTE: It is possible this oldCrypt will still be needed if the final flight is the CCS/FINISHED pair only and the application has built in the smarts to resend if no app data is received. This problem would manifest itself in a failed cipher init and the solution would be to hold off this free until application data is exchanged */ if (ssl->sec.oldCrypt != CK_INVALID_HANDLE && ssl->sec.oldCrypt != ssl->sec.pkcs11Ses) { pkcs11CloseSession(ssl->sec.oldCrypt); ssl->sec.oldCrypt = CK_INVALID_HANDLE; } #endif } return rc; }