/* Encode (encrypt) 'len' bytes of plaintext data that has been placed into the buffer given by matrixSslGetWritebuf(). This is an in-situ encode. CAN ONLY BE CALLED AFTER A PREVIOUS CALL TO matrixSslGetWritebuf len >= 0.If len is zero, we send out a blank ssl record len must be <= size returned by matrixSslGetWritebuf() Returns < 0 on error, total #bytes in outgoing data buf on success */ int32 matrixSslEncodeWritebuf(ssl_t *ssl, uint32 len) { unsigned char *origbuf; int32 rc, reserved; if (!ssl || ((int32)len < 0)) { return PS_ARG_FAIL; } if (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT) { return PS_PROTOCOL_FAIL; } psAssert(ssl->outsize > 0 && ssl->outbuf != NULL); /* Caller was given proper locations and lengths in GetWritebuf() */ origbuf = ssl->outbuf + ssl->outlen; if (ssl->outbuf == NULL || (ssl->outsize - ssl->outlen) < (int32)len) { return PS_FAILURE; } reserved = ssl->recordHeadLen; #ifdef USE_BEAST_WORKAROUND if (ssl->bFlags & BFLAG_STOP_BEAST) { rc = ((ssl->enMacSize + 1) % ssl->enBlockSize) ? ssl->enBlockSize : 0; reserved += ssl->recordHeadLen + rc + (ssl->enBlockSize * ((ssl->enMacSize + 1)/ssl->enBlockSize)) - 1; } #endif #ifdef USE_TLS_1_1 /* If a block cipher is being used TLS 1.1 requires the use of an explicit IV. This is an extra random block of data prepended to the plaintext before encryption. Account for that extra length here. */ if ((ssl->flags & SSL_FLAGS_WRITE_SECURE) && (ssl->flags & SSL_FLAGS_TLS_1_1) && (ssl->enBlockSize > 1)) { reserved += ssl->enBlockSize; } #if defined(USE_TLS_1_2) && defined(USE_AES_GCM) if ((ssl->flags & SSL_FLAGS_TLS_1_2) && (ssl->flags & SSL_FLAGS_GMAC_W)) { reserved += ssl->nonceCtrLen; } #endif /* USE_TLS_1_2 && AES_GCM */ #endif /* USE_TLS_1_1 */ rc = matrixSslEncode(ssl, origbuf, (ssl->outsize - ssl->outlen), origbuf + reserved, &len); if (rc < 0) { psAssert(rc != SSL_FULL); /* should not happen */ return PS_FAILURE; } #ifdef USE_MATRIXSSL_STATS matrixsslUpdateStat(ssl, APP_DATA_SENT_STAT, len); #endif ssl->outlen += len; return ssl->outlen; }
/* This public API allows the user to encrypt the plaintext buffer of their choice into the internal outbuf that is retrieved when matrixSslGetOutdata is called. This is non-in-situ support and will leave the callers plaintext buffer intact ptBuf The plaintext buffer to be converted into an SSL application data record. len The length, in bytes, of the ptBuf plaintext data Returns < 0 on error, total #bytes in outgoing data buf on success */ int32 matrixSslEncodeToOutdata(ssl_t *ssl, unsigned char *ptBuf, uint32 len) { unsigned char *internalBuf; int32 rc, fragLen, recLen, index; if (!ssl || !ptBuf) { return PS_ARG_FAIL; } if (ssl->bFlags & BFLAG_CLOSE_AFTER_SENT) { return PS_PROTOCOL_FAIL; } #ifdef USE_DTLS if (ssl->flags & SSL_FLAGS_DTLS) { rc = matrixSslGetEncodedSize(ssl, len); if (rc > matrixDtlsGetPmtu()) { return PS_LIMIT_FAIL; } } #endif /* Fragmentation support */ index = 0; while (len > 0) { /* We just call matrixSslGetWritebuf to prepare the buffer */ if ((rc = matrixSslGetWritebuf(ssl, &internalBuf, len)) < 0) { psTraceIntInfo("matrixSslEncodeToOutbuf allocation error: %d\n", rc); return rc; } recLen = fragLen = min((uint32)rc, len); psAssert(ssl->outsize > 0 && ssl->outbuf != NULL); if (ssl->outbuf == NULL || (ssl->outsize - ssl->outlen) < (int32)fragLen) { return PS_FAILURE; } internalBuf = ssl->outbuf + ssl->outlen; rc = matrixSslEncode(ssl, internalBuf, (ssl->outsize - ssl->outlen), ptBuf + index, (uint32*)&fragLen); if (rc < 0) { psAssert(rc != SSL_FULL); /* should not happen */ return PS_FAILURE; } index += recLen; len -= recLen; #ifdef USE_MATRIXSSL_STATS matrixsslUpdateStat(ssl, APP_DATA_SENT_STAT, fragLen); #endif ssl->outlen += fragLen; } return ssl->outlen; }