Commit a9aee608 authored by Martin Thomson's avatar Martin Thomson

Bug 1385203 - Use sslBuffer for encoding more widely, r=ekr

This removes ssl3_Append[Number]ToItem and switches more places to using
buffers.  The advantage with that, aside from a consistent interface, is that
encoding using sslBuffer is length checked.  A new field is added to the struct
so that it can be used for encoding directly onto the stack rather than relying
on reallocation when the space limit is reached.

New macros are added so that the internals of sslBuffer aren't accessed
directly.  Not all instances of these accesses have been fixed.

Differential Revision: https://nss-review.dev.mozaws.net/D390

--HG--
branch : NSS_TLS13_DRAFT19_BRANCH
extra : rebase_source : 60595ab46e30d80dc8bd13a341053edd5cd907b6
extra : amend_source : 25edd67ac2d8bda91a4f927c8671cabd257ccba7
parent 0b670220
......@@ -758,12 +758,14 @@ TEST_F(TlsConnectTest, SendSessionTicketMassiveToken) {
Connect();
// It should be safe to set length with a NULL token because the length should
// be checked before reading token.
EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0xffff))
<< "no special tickets in TLS 1.2";
EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0x1ffff))
<< "this is clearly too big";
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), NULL, 0x1ffff))
<< "no special tickets in TLS 1.2";
static const uint8_t big_token[0xffff] = {1};
EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), big_token,
sizeof(big_token)))
<< "this is too big, but that's not immediately obvious";
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
}
......
......@@ -121,12 +121,11 @@ ssl_SelfEncryptProtectInt(
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
{
unsigned int len;
unsigned int lenOffset;
unsigned char iv[AES_BLOCK_SIZE];
SECItem ivItem = { siBuffer, iv, sizeof(iv) };
unsigned char mac[SHA256_LENGTH]; /* SHA-256 */
unsigned int macLen;
SECItem outItem = { siBuffer, out, maxOutLen };
SECItem lengthBytesItem;
/* Write directly to out. */
sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
SECStatus rv;
/* Generate a random IV */
......@@ -137,52 +136,54 @@ ssl_SelfEncryptProtectInt(
}
/* Add header. */
rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv));
rv = sslBuffer_Append(&buf, iv, sizeof(iv));
if (rv != SECSuccess) {
return SECFailure;
}
/* Skip forward by two so we can encode the ciphertext in place. */
lengthBytesItem = outItem;
rv = ssl3_AppendNumberToItem(&outItem, 0, 2);
/* Leave space for the length of the ciphertext. */
rv = sslBuffer_Skip(&buf, 2, &lenOffset);
if (rv != SECSuccess) {
return SECFailure;
}
/* Encode the ciphertext in place. */
rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
outItem.data, &len, outItem.len, in, inLen);
SSL_BUFFER_NEXT(&buf), &len,
SSL_BUFFER_SPACE(&buf), in, inLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Skip(&buf, len, NULL);
if (rv != SECSuccess) {
return SECFailure;
}
outItem.data += len;
outItem.len -= len;
/* Now encode the ciphertext length. */
rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2);
rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* MAC the entire output buffer and append the MAC to the end. */
/* MAC the entire output buffer into the output. */
PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
out, outItem.data - out,
mac, &macLen, sizeof(mac));
SSL_BUFFER_BASE(&buf), /* input */
SSL_BUFFER_LEN(&buf),
SSL_BUFFER_NEXT(&buf), &len, /* output */
SHA256_LENGTH);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert(macLen == sizeof(mac));
rv = ssl3_AppendToItem(&outItem, mac, macLen);
rv = sslBuffer_Skip(&buf, len, NULL);
if (rv != SECSuccess) {
return SECFailure;
}
*outLen = outItem.data - out;
*outLen = SSL_BUFFER_LEN(&buf);
return SECSuccess;
}
......@@ -270,16 +271,14 @@ ssl_SelfEncryptUnprotectInt(
#endif
/* Predict the size of the encrypted data, including padding */
SECStatus
ssl_SelfEncryptGetProtectedSize(unsigned int inLen, unsigned int *outLen)
unsigned int
ssl_SelfEncryptGetProtectedSize(unsigned int inLen)
{
*outLen = SELF_ENCRYPT_KEY_NAME_LEN +
AES_BLOCK_SIZE +
2 +
((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
SHA256_LENGTH;
return SECSuccess;
return SELF_ENCRYPT_KEY_NAME_LEN +
AES_BLOCK_SIZE +
2 +
((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
SHA256_LENGTH;
}
SECStatus
......
......@@ -13,8 +13,7 @@
typedef struct sslSocketStr sslSocket;
SECStatus ssl_SelfEncryptGetProtectedSize(unsigned int inLen,
unsigned int *outLen);
unsigned int ssl_SelfEncryptGetProtectedSize(unsigned int inLen);
SECStatus ssl_SelfEncryptProtect(
sslSocket *ss, const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen);
......
......@@ -70,9 +70,6 @@ static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
#define MIN_SEND_BUF_LENGTH 4000
/* This list of SSL3 cipher suites is sorted in descending order of
* precedence (desirability). It only includes cipher suites we implement.
* This table is modified by SSL3_SetPolicy(). The ordering of cipher suites
......@@ -1431,69 +1428,76 @@ static SECStatus
ssl3_ComputeDHKeyHash(sslSocket *ss, SSLHashType hashAlg, SSL3Hashes *hashes,
SECItem dh_p, SECItem dh_g, SECItem dh_Ys, PRBool padY)
{
PRUint8 *hashBuf;
PRUint8 *pBuf;
SECStatus rv = SECSuccess;
unsigned int bufLen, yLen;
PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8];
sslBuffer buf = SSL_BUFFER_EMPTY;
SECStatus rv;
unsigned int yLen;
unsigned int i;
PORT_Assert(dh_p.data);
PORT_Assert(dh_g.data);
PORT_Assert(dh_Ys.data);
yLen = padY ? dh_p.len : dh_Ys.len;
bufLen = 2 * SSL3_RANDOM_LENGTH +
2 + dh_p.len +
2 + dh_g.len +
2 + yLen;
if (bufLen <= sizeof buf) {
hashBuf = buf;
} else {
hashBuf = PORT_Alloc(bufLen);
if (!hashBuf) {
return SECFailure;
}
rv = sslBuffer_Append(&buf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
memcpy(hashBuf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
pBuf = hashBuf + SSL3_RANDOM_LENGTH;
memcpy(pBuf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
pBuf += SSL3_RANDOM_LENGTH;
pBuf = ssl_EncodeUintX(dh_p.len, 2, pBuf);
memcpy(pBuf, dh_p.data, dh_p.len);
pBuf += dh_p.len;
pBuf = ssl_EncodeUintX(dh_g.len, 2, pBuf);
memcpy(pBuf, dh_g.data, dh_g.len);
pBuf += dh_g.len;
pBuf = ssl_EncodeUintX(yLen, 2, pBuf);
if (padY && dh_p.len > dh_Ys.len) {
memset(pBuf, 0, dh_p.len - dh_Ys.len);
pBuf += dh_p.len - dh_Ys.len;
rv = sslBuffer_Append(&buf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
/* p */
rv = sslBuffer_AppendVariable(&buf, dh_p.data, dh_p.len, 2);
if (rv != SECSuccess) {
goto loser;
}
/* g */
rv = sslBuffer_AppendVariable(&buf, dh_g.data, dh_g.len, 2);
if (rv != SECSuccess) {
goto loser;
}
/* y - complicated by padding */
yLen = padY ? dh_p.len : dh_Ys.len;
rv = sslBuffer_AppendNumber(&buf, yLen, 2);
if (rv != SECSuccess) {
goto loser;
}
/* If we're padding Y, dh_Ys can't be longer than dh_p. */
PORT_Assert(!padY || dh_p.len >= dh_Ys.len);
memcpy(pBuf, dh_Ys.data, dh_Ys.len);
pBuf += dh_Ys.len;
PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
for (i = dh_Ys.len; i < yLen; ++i) {
rv = sslBuffer_AppendNumber(&buf, 0, 1);
if (rv != SECSuccess) {
goto loser;
}
}
rv = sslBuffer_Append(&buf, dh_Ys.data, dh_Ys.len);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes);
rv = ssl3_ComputeCommonKeyHash(hashAlg, SSL_BUFFER_BASE(&buf),
SSL_BUFFER_LEN(&buf), hashes);
if (rv != SECSuccess) {
goto loser;
}
PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen));
if (rv == SECSuccess) {
if (hashAlg == ssl_hash_none) {
PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
hashes->u.s.md5, MD5_LENGTH));
PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
hashes->u.s.sha, SHA1_LENGTH));
} else {
PRINT_BUF(95, (NULL, "DHkey hash: result",
hashes->u.raw, hashes->len));
}
PRINT_BUF(95, (NULL, "DHkey hash: ", SSL_BUFFER_BASE(&buf),
SSL_BUFFER_LEN(&buf)));
if (hashAlg == ssl_hash_none) {
PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
hashes->u.s.md5, MD5_LENGTH));
PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
hashes->u.s.sha, SHA1_LENGTH));
} else {
PRINT_BUF(95, (NULL, "DHkey hash: result",
hashes->u.raw, hashes->len));
}
if (hashBuf != buf && hashBuf != NULL)
PORT_Free(hashBuf);
return rv;
sslBuffer_Clear(&buf);
return SECSuccess;
loser:
sslBuffer_Clear(&buf);
return SECFailure;
}
/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */
......@@ -2544,24 +2548,71 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec,
return SECSuccess;
}
/* Note: though this can report failure, it shouldn't. */
SECStatus
ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
PRBool capRecordVersion, SSL3ContentType type,
unsigned int len, sslBuffer *wrBuf)
{
SSL3ProtocolVersion version = cwSpec->version;
PRBool isTLS13 = (PRBool)(version >= SSL_LIBRARY_VERSION_TLS_1_3);
SECStatus rv;
#ifndef UNSAFE_FUZZER_MODE
if (isTLS13 && cwSpec->cipher_def->calg != ssl_calg_null) {
rv = sslBuffer_AppendNumber(wrBuf, content_application_data, 1);
} else
#endif
{
rv = sslBuffer_AppendNumber(wrBuf, type, 1);
}
if (rv != SECSuccess) {
return SECFailure;
}
if (IS_DTLS(ss)) {
version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
version = dtls_TLSVersionToDTLSVersion(version);
rv = sslBuffer_AppendNumber(wrBuf, version, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(wrBuf, cwSpec->write_seq_num, 8);
if (rv != SECSuccess) {
return SECFailure;
}
} else {
if (capRecordVersion || isTLS13) {
version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
}
rv = sslBuffer_AppendNumber(wrBuf, version, 2);
if (rv != SECSuccess) {
return SECFailure;
}
}
rv = sslBuffer_AppendNumber(wrBuf, len, 2);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
SECStatus
ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
PRBool capRecordVersion, SSL3ContentType type,
const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
{
const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
PRUint16 headerLen;
sslBuffer protBuf;
SSL3ProtocolVersion version = cwSpec->version;
unsigned int headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH
: SSL3_RECORD_HEADER_LENGTH;
sslBuffer protBuf = SSL_BUFFER_FIXED(SSL_BUFFER_BASE(wrBuf) + headerLen,
SSL_BUFFER_SPACE(wrBuf) - headerLen);
PRBool isTLS13;
PRUint8 *ptr = wrBuf->buf;
SECStatus rv;
headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
protBuf.buf = wrBuf->buf + headerLen;
protBuf.len = 0;
protBuf.space = wrBuf->space - headerLen;
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
PORT_Assert(cipher_def->max_records <= RECORD_SEQ_MAX);
if ((cwSpec->write_seq_num & RECORD_SEQ_MAX) >= cipher_def->max_records) {
SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
......@@ -2573,8 +2624,16 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
isTLS13 = (PRBool)(cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3);
#ifdef UNSAFE_FUZZER_MODE
rv = Null_Cipher(NULL, protBuf.buf, (int *)&protBuf.len, protBuf.space,
pIn, contentLen);
{
int len;
rv = Null_Cipher(NULL, SSL_BUFFER_BASE(&protBuf), &len,
SSL_BUFFER_SPACE(&protBuf), pIn, contentLen);
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
rv = sslBuffer_Skip(&protBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
}
#else
if (isTLS13) {
rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf);
......@@ -2589,32 +2648,113 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
}
PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024));
wrBuf->len = protBuf.len + headerLen;
#ifndef UNSAFE_FUZZER_MODE
if (isTLS13 && cipher_def->calg != ssl_calg_null) {
*ptr++ = content_application_data;
} else
#endif
{
*ptr++ = type;
rv = ssl_InsertRecordHeader(ss, cwSpec, capRecordVersion, type,
SSL_BUFFER_LEN(&protBuf), wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
if (IS_DTLS(ss)) {
version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
version = dtls_TLSVersionToDTLSVersion(version);
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == headerLen);
rv = sslBuffer_Skip(wrBuf, SSL_BUFFER_LEN(&protBuf), NULL);
if (rv != SECSuccess) {
PORT_Assert(0); /* Can't fail. */
return SECFailure;
}
++cwSpec->write_seq_num;
return SECSuccess;
}
SECStatus
ssl_ProtectRecordMaybeSplit(sslSocket *ss, ssl3CipherSpec *cwSpec,
SSL3ContentType type, PRBool capRecordVersion,
const PRUint8 *pIn, unsigned int nIn,
unsigned int *written)
{
sslBuffer *wrBuf = &ss->sec.writeBuf;
unsigned int contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
unsigned int spaceNeeded;
unsigned int numRecords;
SECStatus rv;
ptr = ssl_EncodeUintX(version, 2, ptr);
ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr);
if (nIn > 1 && ss->opt.cbcRandomIV &&
ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_1 &&
type == content_application_data &&
ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) {
/* We will split the first byte of the record into its own record,
* as explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h
*/
numRecords = 2;
} else {
if (capRecordVersion || isTLS13) {
version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
numRecords = 1;
}
spaceNeeded = contentLen + (numRecords * SSL3_BUFFER_FUDGE);
if (ss->ssl3.cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
ss->ssl3.cwSpec->cipher_def->type == type_block) {
spaceNeeded += ss->ssl3.cwSpec->cipher_def->iv_size;
}
if (spaceNeeded > SSL_BUFFER_SPACE(wrBuf)) {
rv = sslBuffer_Grow(wrBuf, spaceNeeded);
if (rv != SECSuccess) {
SSL_DBG(("%d: SSL3[%d]: expand write buffer to %d bytes",
SSL_GETPID(), ss->fd, spaceNeeded));
return SECFailure;
}
ptr = ssl_EncodeUintX(version, 2, ptr);
}
(void)ssl_EncodeUintX(protBuf.len, 2, ptr);
++cwSpec->write_seq_num;
if (numRecords == 2) {
rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
pIn, 1, wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
SSL_BUFFER_BASE(wrBuf), SSL_BUFFER_LEN(wrBuf)));
{
sslBuffer secondRecord = SSL_BUFFER_FIXED(SSL_BUFFER_NEXT(wrBuf),
SSL_BUFFER_SPACE(wrBuf));
rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
pIn + 1, contentLen - 1, &secondRecord);
if (rv != SECSuccess) {
return SECFailure;
}
PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
SSL_BUFFER_BASE(&secondRecord),
SSL_BUFFER_LEN(&secondRecord)));
rv = sslBuffer_Skip(wrBuf, SSL_BUFFER_LEN(&secondRecord), NULL);
if (rv != SECSuccess) {
return SECFailure;
}
}
} else {
ssl3CipherSpec *spec;
if (cwSpec) {
/* cwSpec can only be set for retransmissions of DTLS handshake
* messages. */
PORT_Assert(IS_DTLS(ss) &&
(type == content_handshake ||
type == content_change_cipher_spec));
spec = cwSpec;
} else {
spec = ss->ssl3.cwSpec;
}
rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion,
type, pIn, contentLen, wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
PRINT_BUF(50, (ss, "send (encrypted) record data:",
SSL_BUFFER_BASE(wrBuf), SSL_BUFFER_LEN(wrBuf)));
}
*written = contentLen;
return SECSuccess;
}
......@@ -2661,7 +2801,6 @@ ssl3_SendRecord(sslSocket *ss,
SECStatus rv;
PRInt32 totalSent = 0;
PRBool capRecordVersion;
ssl3CipherSpec *spec;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
......@@ -2703,84 +2842,15 @@ ssl3_SendRecord(sslSocket *ss,
}
while (nIn > 0) {
PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
unsigned int spaceNeeded;
unsigned int numRecords;
unsigned int contentLen = 0;
ssl_GetSpecReadLock(ss); /********************************/
if (nIn > 1 && ss->opt.cbcRandomIV &&
ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_1 &&
type == content_application_data &&
ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) {
/* We will split the first byte of the record into its own record,
* as explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h
*/
numRecords = 2;
} else {
numRecords = 1;
}
spaceNeeded = contentLen + (numRecords * SSL3_BUFFER_FUDGE);
if (ss->ssl3.cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
ss->ssl3.cwSpec->cipher_def->type == type_block) {
spaceNeeded += ss->ssl3.cwSpec->cipher_def->iv_size;
}
if (spaceNeeded > wrBuf->space) {
rv = sslBuffer_Grow(wrBuf, spaceNeeded);
if (rv != SECSuccess) {
SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
SSL_GETPID(), ss->fd, spaceNeeded));
goto spec_locked_loser; /* sslBuffer_Grow set error code. */
}
}
if (numRecords == 2) {
sslBuffer secondRecord;
rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
pIn, 1, wrBuf);
if (rv != SECSuccess)
goto spec_locked_loser;
PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
wrBuf->buf, wrBuf->len));
secondRecord.buf = wrBuf->buf + wrBuf->len;
secondRecord.len = 0;
secondRecord.space = wrBuf->space - wrBuf->len;
rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
pIn + 1, contentLen - 1, &secondRecord);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
secondRecord.buf, secondRecord.len));
wrBuf->len += secondRecord.len;
}
} else {
if (cwSpec) {
/* cwSpec can only be set for retransmissions of DTLS handshake
* messages. */
PORT_Assert(IS_DTLS(ss) &&
(type == content_handshake ||
type == content_change_cipher_spec));
spec = cwSpec;
} else {
spec = ss->ssl3.cwSpec;
}
rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion,
type, pIn, contentLen, wrBuf);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data:",
wrBuf->buf, wrBuf->len));
}
}
spec_locked_loser:
rv = ssl_ProtectRecordMaybeSplit(ss, cwSpec, type, capRecordVersion,
pIn, nIn, &contentLen);
ssl_ReleaseSpecReadLock(ss); /************************************/
if (rv != SECSuccess)
if (rv != SECSuccess) {
return SECFailure;
}
pIn += contentLen;
nIn -= contentLen;
......@@ -2793,12 +2863,12 @@ ssl3_SendRecord(sslSocket *ss,
if ((ss->pendingBuf.len > 0) ||
(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len);
rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf),
SSL_BUFFER_LEN(wrBuf));
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
return SECFailure;
}
wrBuf->len = 0; /* All cipher text is saved away. */
if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
PRInt32 sent;
......@@ -2812,10 +2882,13 @@ ssl3_SendRecord(sslSocket *ss,
flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER;
}
}
} else if (wrBuf->len > 0) {
} else {
PRInt32 sent;
PORT_Assert(SSL_BUFFER_LEN(wrBuf) > 0);
ss->handshakeBegun = 1;
sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len,
sent = ssl_DefSend(ss, SSL_BUFFER_BASE(wrBuf),
SSL_BUFFER_LEN(wrBuf),
flags & ~ssl_SEND_FLAG_MASK);
if (sent < 0) {
if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
......@@ -2825,8 +2898,7 @@ ssl3_SendRecord(sslSocket *ss,
/* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */
sent = 0;
}
wrBuf->len -= sent;
if (wrBuf->len) {
if (SSL_BUFFER_LEN(wrBuf) > sent) {
if (IS_DTLS(ss)) {
/* DTLS just says no in this case. No buffering */
PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
......@@ -2835,13 +2907,15 @@ ssl3_SendRecord(sslSocket *ss,
/* now take all the remaining unsent new ciphertext and
* append it to the buffer of previously unsent ciphertext.
*/
rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len);
rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf) + sent,
SSL_BUFFER_LEN(wrBuf) - sent);
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
return SECFailure;
}
}
}
wrBuf->len = 0;
totalSent += contentLen;
}
return totalSent;
......@@ -4147,96 +4221,6 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l
return rv;
}
/**************************************************************************
* Append Handshake functions.
* All these functions set appropriate error codes.
* Most rely on ssl3_AppendHandshake to set the error code.
**************************************************************************/
SECStatus
ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
{
unsigned char *src = (unsigned char *)void_src;
int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */
if (!bytes)
return SECSuccess;
if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) {
rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH,
PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes)));
if (rv != SECSuccess)
return rv; /* sslBuffer_Grow has set a memory error code. */
room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
}
PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes));
rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
if (rv != SECSuccess)
return rv; /* error code set by ssl3_UpdateHandshakeHashes */
while (bytes > room) {
if (room > 0)
PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src,
room);
ss->sec.ci.sendBuf.len += room;
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (rv != SECSuccess) {
return rv; /* error code set by ssl3_FlushHandshake */
}
bytes -= room;
src += room;
room = ss->sec.ci.sendBuf.space;
PORT_Assert(ss->sec.ci.sendBuf.len == 0);
}
PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes);
ss->sec.ci.sendBuf.len += bytes;
return SECSuccess;
}
SECStatus
ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, unsigned int lenSize)
{