summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelsonb%netscape.com <devnull@localhost>2005-12-21 10:02:57 +0000
committernelsonb%netscape.com <devnull@localhost>2005-12-21 10:02:57 +0000
commita89cac6f3f712a5dad2846f08ca7247552b745b9 (patch)
tree06d5ae7f3e424d7f730cf0031c9f77a1208a33eb
parent1f0f973bddb4c9d37959bc8f8a3893fa0ac709f7 (diff)
downloadnss-hg-a89cac6f3f712a5dad2846f08ca7247552b745b9.tar.gz
test patch for bug 80092, off of the 3.11 branch.
-rw-r--r--security/nss/cmd/selfserv/selfserv.c74
-rw-r--r--security/nss/lib/softoken/pcertdb.c2
-rw-r--r--security/nss/lib/ssl/ssl3con.c446
-rw-r--r--security/nss/lib/ssl/sslcon.c10
-rw-r--r--security/nss/lib/ssl/ssldef.c54
-rw-r--r--security/nss/lib/ssl/sslimpl.h6
-rw-r--r--security/nss/lib/ssl/sslsecur.c44
7 files changed, 355 insertions, 281 deletions
diff --git a/security/nss/cmd/selfserv/selfserv.c b/security/nss/cmd/selfserv/selfserv.c
index f4a3e6525..630455993 100644
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -937,6 +937,7 @@ handle_connection(
int newln = 0; /* # of consecutive newlns */
int firstTime = 1;
int reqLen;
+ int cLen = 0;
int rv;
int numIOVs;
PRSocketOptionData opt;
@@ -984,9 +985,9 @@ handle_connection(
}
}
- while (1) {
- newln = 0;
- reqLen = 0;
+ newln = 0;
+ reqLen = 0;
+ while (bufRem > 1 && newln < 2) {
rv = PR_Read(ssl_sock, pBuf, bufRem - 1);
if (rv == 0 ||
(rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) {
@@ -1021,35 +1022,56 @@ handle_connection(
newln = 0;
}
}
-
+
/* came to the end of the buffer, or second newln
* If we didn't get an empty line (CRLFCRLF) then keep on reading.
*/
- if (newln < 2)
- continue;
+ } /* read header loop */
+ if (newln < 2) {
+ /* http request header exceeded our buffer size. Punt. */
+ goto cleanup;
+ }
+ buf[reqLen - 1] = 0; /* plant NULL at end of request header */
- /* we're at the end of the HTTP request.
- * If the request is a POST, then there will be one more
- * line of data.
- * This parsing is a hack, but ok for SSL test purposes.
- */
- post = PORT_Strstr(buf, "POST ");
- if (!post || *post != 'P')
- break;
+ /* we're at the end of the HTTP request.
+ * If the request is a POST, then there will be more data.
+ * This parsing is a hack, but ok for SSL test purposes.
+ */
+ post = PORT_Strstr(buf, "POST ");
+ if (post && *post == 'P') {
+ /* It's a post. Look for the Content-Length header */
+ post = PORT_Strstr(buf, "Content-Length:");
+ if (post && *post == 'C') {
+ post += 15;
+ cLen = atoi(post);
+ }
+ if (cLen <= 0) {
+ /* invalid input format, drop the rest */
+ goto send_reply;
+ }
- /* It's a post, so look for the next and final CR/LF. */
- /* We should parse content length here, but ... */
- while (reqLen < bufDat && newln < 3) {
- int octet = buf[reqLen++];
- if (octet == '\n') {
- newln++;
+ if (reqLen < bufDat) {
+ cLen -= bufDat - reqLen;
+ }
+ while (cLen > 0) { /* discard cLen characters */
+ int toRead = PR_MIN(cLen, (sizeof fileName) - 1);
+ rv = PR_Read(ssl_sock, fileName, toRead);
+ if (rv == 0 ||
+ (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) {
+ if (verbose)
+ errWarn("HDX PR_Read hit EOF");
+ break;
}
+ if (rv < 0) {
+ errWarn("HDX PR_Read");
+ goto cleanup;
+ }
+ cLen -= rv;
+ bufDat += rv;
}
- if (newln == 3)
- break;
- } /* read loop */
+ } /* POST */
- bufDat = pBuf - buf;
+ buf[reqLen - 1] = '\n'; /* bufDat = pBuf - buf; */
if (bufDat) do { /* just close if no data */
/* Have either (a) a complete get, (b) a complete post, (c) EOF */
if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) {
@@ -1115,7 +1137,7 @@ handle_connection(
}
}
}
-
+send_reply:
numIOVs = 0;
iovs[numIOVs].iov_base = (char *)outHeader;
@@ -1151,7 +1173,7 @@ handle_connection(
if (reload_crl(local_file_fd) == SECFailure) {
errString = errWarn("CERT_CacheCRL");
if (!errString)
- errString = "Unknow error";
+ errString = "Unknown error";
PR_snprintf(msgBuf, sizeof(msgBuf), "%s%s ",
crlCacheErr, errString);
diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/pcertdb.c
index 4a7706378..e0a719e1f 100644
--- a/security/nss/lib/softoken/pcertdb.c
+++ b/security/nss/lib/softoken/pcertdb.c
@@ -3849,6 +3849,8 @@ UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
updatehandle.permCertDB = updatedb;
updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB);
+ updatehandle.dbVerify = 0;
+ updatehandle.ref = 1; /* prevent premature close */
rv = nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback,
(void *)handle);
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 2b34b9519..6e87605aa 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1693,32 +1693,166 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) {
return isPresent;
}
+static SECStatus
+ssl3_CompressMACEncryptRecord(sslSocket * ss,
+ SSL3ContentType type,
+ const SSL3Opaque * pIn,
+ PRUint32 contentLen)
+{
+ ssl3CipherSpec * cwSpec;
+ const ssl3BulkCipherDef * cipher_def;
+ sslBuffer * wrBuf = &ss->sec.writeBuf;
+ SECStatus rv;
+ PRUint32 macLen = 0;
+ PRUint32 fragLen;
+ PRUint32 p1Len, p2Len, oddLen = 0;
+ PRInt32 cipherBytes = 0;
+
+ /*
+ * null compression is easy to do
+ PORT_Memcpy(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, pIn, contentLen);
+ */
+
+ ssl_GetSpecReadLock(ss); /********************************/
+
+ cwSpec = ss->ssl3.cwSpec;
+ cipher_def = cwSpec->cipher_def;
+ /*
+ * Add the MAC
+ */
+ rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer),
+ type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
+ wrBuf->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+ goto spec_locked_loser;
+ }
+ p1Len = contentLen;
+ p2Len = macLen;
+ fragLen = contentLen + macLen; /* needs to be encrypted */
+ PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
+
+ /*
+ * Pad the text (if we're doing a block cipher)
+ * then Encrypt it
+ */
+ if (cipher_def->type == type_block) {
+ unsigned char * pBuf;
+ int padding_length;
+ int i;
+
+ oddLen = contentLen % cipher_def->block_size;
+ /* Assume blockSize is a power of two */
+ padding_length = cipher_def->block_size - 1 -
+ ((fragLen) & (cipher_def->block_size - 1));
+ fragLen += padding_length + 1;
+ PORT_Assert((fragLen % cipher_def->block_size) == 0);
+
+ /* Pad according to TLS rules (also acceptable to SSL3). */
+ pBuf = &wrBuf->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1];
+ for (i = padding_length + 1; i > 0; --i) {
+ *pBuf-- = padding_length;
+ }
+ /* now, if contentLen is not a multiple of block size, fix it */
+ p2Len = fragLen - p1Len;
+ }
+ if (p1Len < 256) {
+ oddLen = p1Len;
+ p1Len = 0;
+ } else {
+ p1Len -= oddLen;
+ }
+ if (oddLen) {
+ p2Len += oddLen;
+ PORT_Assert( (cipher_def->block_size < 2) || \
+ (p2Len % cipher_def->block_size) == 0);
+ memcpy(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ pIn + p1Len, oddLen);
+ }
+ if (p1Len > 0) {
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, /* output */
+ &cipherBytes, /* actual outlen */
+ p1Len, /* max outlen */
+ pIn, p1Len); /* input, and inputlen */
+ PORT_Assert(rv == SECSuccess && cipherBytes == p1Len);
+ if (rv != SECSuccess || cipherBytes != p1Len) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ goto spec_locked_loser;
+ }
+ }
+ if (p2Len > 0) {
+ PRInt32 cipherBytesPart2 = -1;
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ &cipherBytesPart2, /* output and actual outLen */
+ p2Len, /* max outlen */
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ p2Len); /* input and inputLen*/
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
+ if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ goto spec_locked_loser;
+ }
+ cipherBytes += cipherBytesPart2;
+ }
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_ENCRYPTION_FAILURE);
+spec_locked_loser:
+ ssl_ReleaseSpecReadLock(ss);
+ return SECFailure;
+ }
+ PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
+
+ ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
+
+ wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH;
+ wrBuf->buf[0] = type;
+ wrBuf->buf[1] = MSB(cwSpec->version);
+ wrBuf->buf[2] = LSB(cwSpec->version);
+ wrBuf->buf[3] = MSB(cipherBytes);
+ wrBuf->buf[4] = LSB(cipherBytes);
+
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+
+ return SECSuccess;
+}
+
/* Process the plain text before sending it.
* Returns the number of bytes of plaintext that were succesfully sent
* plus the number of bytes of plaintext that were copied into the
* output (write) buffer.
* Returns SECFailure on a hard IO error, memory error, or crypto error.
* Does NOT return SECWouldBlock.
+ *
+ * Notes on the use of the private ssl flags:
+ * (no private SSL flags)
+ * Attempt to make and send SSL records for all plaintext
+ * If non-blocking and a send gets WOULD_BLOCK,
+ * or if the pending (ciphertext) buffer is not empty,
+ * then buffer remaining bytes of ciphertext into pending buf,
+ * and continue to do that for all succssive records until all
+ * bytes are used.
+ * ssl_SEND_FLAG_FORCE_INTO_BUFFER
+ * As above, except this suppresses all write attempts, and forces
+ * all ciphertext into the pending ciphertext buffer.
+ *
*/
static PRInt32
ssl3_SendRecord( sslSocket * ss,
SSL3ContentType type,
- const SSL3Opaque * buf,
- PRInt32 bytes,
+ const SSL3Opaque * pIn, /* input buffer */
+ PRInt32 nIn, /* bytes of input */
PRInt32 flags)
{
- ssl3CipherSpec * cwSpec;
- sslBuffer * write = &ss->sec.writeBuf;
- const ssl3BulkCipherDef * cipher_def;
+ sslBuffer * wrBuf = &ss->sec.writeBuf;
SECStatus rv;
- PRUint32 bufSize = 0;
- PRInt32 sent = 0;
- PRBool isBlocking = ssl_SocketIsBlocking(ss);
+ PRInt32 totalSent = 0;
- SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s bytes=%d",
+ SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
- bytes));
- PRINT_BUF(3, (ss, "Send record (plain text)", buf, bytes));
+ nIn));
+ PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn));
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
@@ -1740,149 +1874,30 @@ ssl3_SendRecord( sslSocket * ss,
return SECFailure;
}
- while (bytes > 0) {
- PRInt32 count;
- PRUint32 contentLen;
- PRUint32 fragLen;
- PRUint32 macLen;
- PRInt32 cipherBytes = 0;
- PRUint32 p1Len, p2Len, oddLen = 0;
+ while (nIn > 0) {
+ PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
- contentLen = PR_MIN(bytes, MAX_FRAGMENT_LENGTH);
- if (write->space < contentLen + SSL3_BUFFER_FUDGE) {
- rv = sslBuffer_Grow(write, contentLen + SSL3_BUFFER_FUDGE);
+ if (wrBuf->space < contentLen + SSL3_BUFFER_FUDGE) {
+ PRInt32 newSpace = PR_MAX(wrBuf->space * 2, contentLen);
+ newSpace = PR_MIN(newSpace, MAX_FRAGMENT_LENGTH);
+ newSpace += SSL3_BUFFER_FUDGE;
+ rv = sslBuffer_Grow(wrBuf, newSpace);
if (rv != SECSuccess) {
SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
- SSL_GETPID(), ss->fd, contentLen + SSL3_BUFFER_FUDGE));
+ SSL_GETPID(), ss->fd, newSpace));
return SECFailure; /* sslBuffer_Grow set a memory error code. */
}
}
- /* This variable records the actual size of the buffer allocated above.
- * Some algorithms may expand the number of bytes needed to send data.
- * If we only supply the output buffer with the same number
- * of bytes as the input buffer, we will fail.
- */
- bufSize = contentLen + SSL3_BUFFER_FUDGE;
-
- /*
- * null compression is easy to do
- PORT_Memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH, buf, contentLen);
- */
-
- ssl_GetSpecReadLock(ss); /********************************/
-
- cwSpec = ss->ssl3.cwSpec;
- cipher_def = cwSpec->cipher_def;
- /*
- * Add the MAC
- */
- rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer),
- type, cwSpec->version, cwSpec->write_seq_num, buf, contentLen,
- write->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
- goto spec_locked_loser;
- }
- p1Len = contentLen;
- p2Len = macLen;
- fragLen = contentLen + macLen; /* needs to be encrypted */
- PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
-
- /*
- * Pad the text (if we're doing a block cipher)
- * then Encrypt it
- */
- if (cipher_def->type == type_block) {
- unsigned char * pBuf;
- int padding_length;
- int i;
-
- oddLen = contentLen % cipher_def->block_size;
- /* Assume blockSize is a power of two */
- padding_length = cipher_def->block_size - 1 -
- ((fragLen) & (cipher_def->block_size - 1));
- fragLen += padding_length + 1;
- PORT_Assert((fragLen % cipher_def->block_size) == 0);
-
- /* Pad according to TLS rules (also acceptable to SSL3). */
- pBuf = &write->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1];
- for (i = padding_length + 1; i > 0; --i) {
- *pBuf-- = padding_length;
- }
- /* now, if contentLen is not a multiple of block size, fix it */
- p2Len = fragLen - p1Len;
- }
- if (p1Len < 256) {
- oddLen = p1Len;
- p1Len = 0;
- } else {
- p1Len -= oddLen;
- }
- if (oddLen) {
- p2Len += oddLen;
- PORT_Assert( (cipher_def->block_size < 2) || \
- (p2Len % cipher_def->block_size) == 0);
- memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
- buf + p1Len, oddLen);
- }
- if (p1Len > 0) {
- rv = cwSpec->encode( cwSpec->encodeContext,
- write->buf + SSL3_RECORD_HEADER_LENGTH, /* output */
- &cipherBytes, /* actual outlen */
- p1Len, /* max outlen */
- buf, p1Len); /* input, and inputlen */
- PORT_Assert(rv == SECSuccess && cipherBytes == p1Len);
- if (rv != SECSuccess || cipherBytes != p1Len) {
- PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
- goto spec_locked_loser;
- }
- }
- if (p2Len > 0) {
- PRInt32 cipherBytesPart2 = -1;
- rv = cwSpec->encode( cwSpec->encodeContext,
- write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
- &cipherBytesPart2, /* output and actual outLen */
- p2Len, /* max outlen */
- write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
- p2Len); /* input and inputLen*/
- PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
- if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
- PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
- goto spec_locked_loser;
- }
- cipherBytes += cipherBytesPart2;
- }
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_ENCRYPTION_FAILURE);
-spec_locked_loser:
- ssl_ReleaseSpecReadLock(ss);
+ rv = ssl3_CompressMACEncryptRecord( ss, type, pIn, contentLen);
+ if (rv != SECSuccess)
return SECFailure;
- }
- PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
-
- /*
- * XXX should we zero out our copy of the buffer after compressing
- * and encryption ??
- */
-
- ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
-
- ssl_ReleaseSpecReadLock(ss); /************************************/
- buf += contentLen;
- bytes -= contentLen;
- PORT_Assert( bytes >= 0 );
+ pIn += contentLen;
+ nIn -= contentLen;
+ PORT_Assert( nIn >= 0 );
- /* PORT_Assert(fragLen == cipherBytes); */
- write->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH;
- write->buf[0] = type;
- write->buf[1] = MSB(cwSpec->version);
- write->buf[2] = LSB(cwSpec->version);
- write->buf[3] = MSB(cipherBytes);
- write->buf[4] = LSB(cipherBytes);
-
- PRINT_BUF(50, (ss, "send (encrypted) record data:", write->buf, write->len));
+ PRINT_BUF(50, (ss, "send (encrypted) record data:", wrBuf->buf, wrBuf->len));
/* If there's still some previously saved ciphertext,
* or the caller doesn't want us to send the data yet,
@@ -1891,59 +1906,57 @@ spec_locked_loser:
if ((ss->pendingBuf.len > 0) ||
(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
- rv = ssl_SaveWriteData(ss, &ss->pendingBuf,
- write->buf, write->len);
+ rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len);
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
return SECFailure;
}
- write->len = 0; /* All cipher text is saved away. */
+ wrBuf->len = 0; /* All cipher text is saved away. */
if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
-
+ PRInt32 sent;
ss->handshakeBegun = 1;
- count = ssl_SendSavedWriteData(ss, &ss->pendingBuf,
- &ssl_DefSend);
- if (count < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ sent = ssl_SendSavedWriteData(ss);
+ if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
return SECFailure;
}
+ if (ss->pendingBuf.len) {
+ flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER;
+ }
}
- } else if (write->len > 0) {
+ } else if (wrBuf->len > 0) {
+ PRInt32 sent;
ss->handshakeBegun = 1;
- count = ssl_DefSend(ss, write->buf, write->len,
- flags & ~ssl_SEND_FLAG_MASK);
- if (count < 0) {
+ sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len,
+ flags & ~ssl_SEND_FLAG_MASK);
+ if (sent < 0) {
if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
- return (sent > 0) ? sent : SECFailure;
+ return SECFailure;
}
/* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */
- count = 0;
+ sent = 0;
}
- /* now take all the remaining unsent newly-generated ciphertext and
- * append it to the buffer of previously unsent ciphertext.
- */
- if ((unsigned)count < write->len) {
- rv = ssl_SaveWriteData(ss, &ss->pendingBuf,
- write->buf + (unsigned)count,
- write->len - (unsigned)count);
+ wrBuf->len -= sent;
+ if (wrBuf->len) {
+ /* 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);
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
return SECFailure;
}
}
- write->len = 0;
- }
- sent += contentLen;
- if ((flags & ssl_SEND_FLAG_NO_BUFFER) &&
- (isBlocking || (ss->pendingBuf.len > 0))) {
- break;
}
+ totalSent += contentLen;
}
- return sent;
+ return totalSent;
}
+#define SSL3_PENDING_HIGH_WATER 1024
+
/* Attempt to send the content of "in" in an SSL application_data record.
* Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess.
*/
@@ -1951,14 +1964,36 @@ int
ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
PRInt32 len, PRInt32 flags)
{
- PRInt32 sent = 0;
+ PRInt32 totalSent = 0;
+ PRInt32 discarded = 0;
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ if (len < 0 || !in) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
- while (len > 0) {
- PRInt32 count;
+ if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER &&
+ !ssl_SocketIsBlocking(ss)) {
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
+ if (ss->appDataBuffered && len) {
+ PORT_Assert (in[0] == (unsigned char)(ss->appDataBuffered));
+ if (in[0] != (unsigned char)(ss->appDataBuffered)) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ in++;
+ len--;
+ discarded = 1;
+ }
+ while (len > totalSent) {
+ PRInt32 sent, toSend;
- if (sent > 0) {
+ if (totalSent > 0) {
/*
* The thread yield is intended to give the reader thread a
* chance to get some cycles while the writer thread is in
@@ -1969,17 +2004,40 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */
ssl_GetXmitBufLock(ss);
}
- count = ssl3_SendRecord(ss, content_application_data, in, len,
- flags | ssl_SEND_FLAG_NO_BUFFER);
- if (count < 0) {
- return (sent > 0) ? sent : count;
- /* error code set by ssl3_SendRecord */
+ toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
+ sent = ssl3_SendRecord(ss, content_application_data,
+ in + totalSent, toSend, flags);
+ if (sent < 0) {
+ if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) {
+ PORT_Assert(ss->lastWriteBlocked);
+ break;
+ }
+ return SECFailure; /* error code set by ssl3_SendRecord */
+ }
+ totalSent += sent;
+ if (ss->pendingBuf.len) {
+ /* must be a non-blocking socket */
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ PORT_Assert(ss->lastWriteBlocked);
+ break;
}
- sent += count;
- len -= count;
- in += count;
}
- return sent;
+ if (ss->pendingBuf.len) {
+ /* Must be non-blocking. */
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ if (totalSent > 0) {
+ ss->appDataBuffered = 0x100 | in[totalSent - 1];
+ }
+
+ totalSent = totalSent + discarded - 1;
+ if (totalSent <= 0) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ totalSent = SECFailure;
+ }
+ return totalSent;
+ }
+ ss->appDataBuffered = 0;
+ return totalSent + discarded;
}
/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
@@ -1995,18 +2053,28 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
static SECStatus
ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
{
- PRInt32 rv;
+ PRInt32 sent = 0;
+ /* only this flag is allowed */
+ PORT_Assert(!(flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
return SECSuccess;
- rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf,
- ss->sec.ci.sendBuf.len, flags);
- if (rv < 0) {
- return (SECStatus)rv; /* error code set by ssl3_SendRecord */
+ while (ss->sec.ci.sendBuf.len > sent) {
+ PRInt32 rv;
+ rv = ssl3_SendRecord(ss, content_handshake,
+ ss->sec.ci.sendBuf.buf + sent,
+ ss->sec.ci.sendBuf.len - sent, flags);
+ if (rv < 0) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR)
+ return SECFailure; /* error code set by ssl3_SendRecord */
+ rv = 0;
+ }
+ flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER;
+ sent += rv;
}
ss->sec.ci.sendBuf.len = 0;
return SECSuccess;
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 06ec09813..a3c01a4cc 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -926,8 +926,8 @@ ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if ((unsigned)rv < (amount + 2)) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- amount + 2 - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv)
+ == SECFailure) {
count = SECFailure;
} else {
count += amount;
@@ -1023,8 +1023,7 @@ ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if ((unsigned)rv < buflen) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- buflen - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) {
count = SECFailure;
} else {
count += amount;
@@ -1152,8 +1151,7 @@ ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if (rv < (op - out)) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- op - out - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) {
count = SECFailure;
} else {
count += amount;
diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c
index 23ef9cafe..9a473380e 100644
--- a/security/nss/lib/ssl/ssldef.c
+++ b/security/nss/lib/ssl/ssldef.c
@@ -104,14 +104,15 @@ int ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
}
/* Default (unencrypted) send.
- * Returns SECSuccess or SECFailure, NOT SECWouldBlock.
- * Returns positive count if any data was written.
- * ALWAYS check for a short write after calling ssl_DefSend.
+ * For blocking sockets, always returns len or SECFailure, no short writes.
+ * For non-blocking sockets:
+ * Returns positive count if any data was written, else returns SECFailure.
+ * Short writes may occur. Does not return SECWouldBlock.
*/
int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
{
PRFileDesc *lower = ss->fd->lower;
- int rv, count;
+ int sent = 0;
#if NSS_DISABLE_NAGLE_DELAYS
/* Although this is overkill, we disable Nagle delays completely for
@@ -122,32 +123,24 @@ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
ss->delayDisabled = 1;
}
#endif
- count = 0;
- for (;;) {
- rv = lower->methods->send(lower, (const void *)buf, len,
- flags, ss->wTimeout);
+ do {
+ int rv = lower->methods->send(lower, (const void *)(buf + sent),
+ len - sent, flags, ss->wTimeout);
if (rv < 0) {
PRErrorCode err = PR_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
ss->lastWriteBlocked = 1;
- return count ? count : rv;
+ return sent ? sent : SECFailure;
}
ss->lastWriteBlocked = 0;
MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
/* Loser */
return rv;
}
- count += rv;
- if (rv < len) {
- /* Short send. Send the rest in the next call */
- buf += rv;
- len -= rv;
- continue;
- }
- break;
- }
+ sent += rv;
+ } while (len > sent);
ss->lastWriteBlocked = 0;
- return count;
+ return sent;
}
int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len)
@@ -166,33 +159,26 @@ int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len)
int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len)
{
PRFileDesc *lower = ss->fd->lower;
- int rv, count;
+ int sent = 0;
- count = 0;
- for (;;) {
- rv = lower->methods->write(lower, (void *)buf, len);
+ do {
+ int rv = lower->methods->write(lower, (const void *)(buf + sent),
+ len - sent);
if (rv < 0) {
PRErrorCode err = PR_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
ss->lastWriteBlocked = 1;
- return count ? count : rv;
+ return sent ? sent : SECFailure;
}
ss->lastWriteBlocked = 0;
MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
/* Loser */
return rv;
}
- count += rv;
- if (rv != len) {
- /* Short write. Send the rest in the next call */
- buf += rv;
- len -= rv;
- continue;
- }
- break;
- }
+ sent += rv;
+ } while (len > sent);
ss->lastWriteBlocked = 0;
- return count;
+ return sent;
}
int ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name)
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 1da55d59b..039db31fb 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -897,6 +897,7 @@ struct sslSocketStr {
unsigned long lastWriteBlocked;
unsigned long recvdCloseNotify; /* received SSL EOF. */
unsigned long TCPconnected;
+ unsigned long appDataBuffered;
/* version of the protocol to use */
SSL3ProtocolVersion version;
@@ -1084,9 +1085,8 @@ extern sslSocket * ssl_DupSocket(sslSocket *old);
extern void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *cp, int len);
extern void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len);
-extern int ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf,
- sslSendFunc fp);
-extern SECStatus ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf,
+extern int ssl_SendSavedWriteData(sslSocket *ss);
+extern SECStatus ssl_SaveWriteData(sslSocket *ss,
const void* p, unsigned int l);
extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss);
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index a30b062df..fdc41079c 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -440,24 +440,23 @@ sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
** Caller must hold xmitBufLock
*/
SECStatus
-ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data,
- unsigned int len)
+ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)
{
unsigned int newlen;
SECStatus rv;
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
- newlen = buf->len + len;
- if (newlen > buf->space) {
- rv = sslBuffer_Grow(buf, newlen);
+ newlen = ss->pendingBuf.len + len;
+ if (newlen > ss->pendingBuf.space) {
+ rv = sslBuffer_Grow(&ss->pendingBuf, newlen);
if (rv) {
return rv;
}
}
SSL_TRC(5, ("%d: SSL[%d]: saving %d bytes of data (%d total saved so far)",
SSL_GETPID(), ss->fd, len, newlen));
- PORT_Memcpy(buf->buf + buf->len, data, len);
- buf->len = newlen;
+ PORT_Memcpy(ss->pendingBuf.buf + ss->pendingBuf.len, data, len);
+ ss->pendingBuf.len = newlen;
return SECSuccess;
}
@@ -468,28 +467,23 @@ ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data,
** Caller must hold xmitBufLock
*/
int
-ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf, sslSendFunc send)
+ssl_SendSavedWriteData(sslSocket *ss)
{
int rv = 0;
- int len = buf->len;
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
- if (len != 0) {
+ if (ss->pendingBuf.len != 0) {
SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data",
- SSL_GETPID(), ss->fd, len));
- rv = (*send)(ss, buf->buf, len, 0);
+ SSL_GETPID(), ss->fd, ss->pendingBuf.len));
+ rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0);
if (rv < 0) {
return rv;
}
- if (rv < len) {
- /* UGH !! This shifts the whole buffer down by copying it, and
- ** it depends on PORT_Memmove doing overlapping moves correctly!
- ** It should advance the pointer offset instead !!
- */
- PORT_Memmove(buf->buf, buf->buf + rv, len - rv);
- buf->len = len - rv;
- } else {
- buf->len = 0;
+ ss->pendingBuf.len -= rv;
+ if (ss->pendingBuf.len > 0 && rv > 0) {
+ /* UGH !! This shifts the whole buffer down by copying it */
+ PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv,
+ ss->pendingBuf.len);
}
}
return rv;
@@ -1017,7 +1011,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) {
ssl_GetXmitBufLock(ss);
if (ss->pendingBuf.len != 0) {
- rv = ssl_SendSavedWriteData(ss, &ss->pendingBuf, ssl_DefSend);
+ rv = ssl_SendSavedWriteData(ss);
if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) {
ssl_ReleaseXmitBufLock(ss);
return SECFailure;
@@ -1072,7 +1066,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
ssl_GetXmitBufLock(ss);
if (ss->pendingBuf.len != 0) {
PORT_Assert(ss->pendingBuf.len > 0);
- rv = ssl_SendSavedWriteData(ss, &ss->pendingBuf, ssl_DefSend);
+ rv = ssl_SendSavedWriteData(ss);
if (rv >= 0 && ss->pendingBuf.len != 0) {
PORT_Assert(ss->pendingBuf.len > 0);
PORT_SetError(PR_WOULD_BLOCK_ERROR);
@@ -1106,6 +1100,10 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
return 0;
}
PORT_Assert(buf != NULL);
+ if (!buf) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return PR_FAILURE;
+ }
SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
SSL_GETPID(), ss->fd, len));