diff options
author | nelsonb%netscape.com <devnull@localhost> | 2005-12-21 10:02:57 +0000 |
---|---|---|
committer | nelsonb%netscape.com <devnull@localhost> | 2005-12-21 10:02:57 +0000 |
commit | a89cac6f3f712a5dad2846f08ca7247552b745b9 (patch) | |
tree | 06d5ae7f3e424d7f730cf0031c9f77a1208a33eb | |
parent | 1f0f973bddb4c9d37959bc8f8a3893fa0ac709f7 (diff) | |
download | nss-hg-a89cac6f3f712a5dad2846f08ca7247552b745b9.tar.gz |
test patch for bug 80092, off of the 3.11 branch.
-rw-r--r-- | security/nss/cmd/selfserv/selfserv.c | 74 | ||||
-rw-r--r-- | security/nss/lib/softoken/pcertdb.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 446 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslcon.c | 10 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssldef.c | 54 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 44 |
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)); |