summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtc%google.com <devnull@localhost>2012-03-13 02:39:11 +0000
committerwtc%google.com <devnull@localhost>2012-03-13 02:39:11 +0000
commitd372055e85ddb75603a8c31d8201075ba8b20ad7 (patch)
tree25956f323856475e186a55ee47256b7e273fb3f9
parent8fe6a1c4d4c61e897becf8dbdd0b29d55cb848e1 (diff)
downloadnss-hg-d372055e85ddb75603a8c31d8201075ba8b20ad7.tar.gz
Bug 565047: Implement TLS 1.1, except for restrictions on export cipher
suites. The patch is written by Brian Smith <bsmith@mozilla.com>. r=wtc. Modified Files: ssl3con.c sslimpl.h sslproto.h
-rw-r--r--security/nss/lib/ssl/ssl3con.c121
-rw-r--r--security/nss/lib/ssl/sslimpl.h3
-rw-r--r--security/nss/lib/ssl/sslproto.h1
3 files changed, 100 insertions, 25 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 94f19cf6b..a7a53ca63 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -2024,21 +2024,51 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
{
const ssl3BulkCipherDef * cipher_def;
SECStatus rv;
- PRUint32 macLen = 0;
+ PRUint32 macLen = 0;
PRUint32 fragLen;
PRUint32 p1Len, p2Len, oddLen = 0;
- PRInt32 cipherBytes = 0;
+ int ivLen = 0;
+ int cipherBytes = 0;
cipher_def = cwSpec->cipher_def;
+ if (cipher_def->type == type_block &&
+ cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Prepend the per-record explicit IV using technique 2b from
+ * RFC 4346 section 6.2.3.2: The IV is a cryptographically
+ * strong random number XORed with the CBC residue from the previous
+ * record.
+ */
+ ivLen = cipher_def->iv_size;
+ if (ivLen > wrBuf->space - SSL3_RECORD_HEADER_LENGTH) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = PK11_GenerateRandom(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, ivLen);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH,
+ &cipherBytes, /* output and actual outLen */
+ ivLen, /* max outlen */
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH,
+ ivLen); /* input and inputLen*/
+ if (rv != SECSuccess || cipherBytes != ivLen) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ return SECFailure;
+ }
+ }
+
if (cwSpec->compressor) {
int outlen;
rv = cwSpec->compressor(
- cwSpec->compressContext, wrBuf->buf + SSL3_RECORD_HEADER_LENGTH,
- &outlen, wrBuf->space - SSL3_RECORD_HEADER_LENGTH, pIn, contentLen);
+ cwSpec->compressContext,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, &outlen,
+ wrBuf->space - SSL3_RECORD_HEADER_LENGTH - ivLen, pIn, contentLen);
if (rv != SECSuccess)
return rv;
- pIn = wrBuf->buf + SSL3_RECORD_HEADER_LENGTH;
+ pIn = wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen;
contentLen = outlen;
}
@@ -2047,7 +2077,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
*/
rv = ssl3_ComputeRecordMAC( cwSpec, isServer,
type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
- wrBuf->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen);
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + contentLen, &macLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
return SECFailure;
@@ -2074,7 +2104,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
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];
+ pBuf = &wrBuf->buf[SSL3_RECORD_HEADER_LENGTH + ivLen + fragLen - 1];
for (i = padding_length + 1; i > 0; --i) {
*pBuf-- = padding_length;
}
@@ -2091,31 +2121,33 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
p2Len += oddLen;
PORT_Assert( (cipher_def->block_size < 2) || \
(p2Len % cipher_def->block_size) == 0);
- memmove(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ memmove(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
pIn + p1Len, oddLen);
}
if (p1Len > 0) {
+ int cipherBytesPart1 = -1;
rv = cwSpec->encode( cwSpec->encodeContext,
- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, /* output */
- &cipherBytes, /* actual outlen */
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, /* output */
+ &cipherBytesPart1, /* actual outlen */
p1Len, /* max outlen */
pIn, p1Len); /* input, and inputlen */
- PORT_Assert(rv == SECSuccess && cipherBytes == p1Len);
- if (rv != SECSuccess || cipherBytes != p1Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
+ if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
+ cipherBytes += cipherBytesPart1;
}
if (p2Len > 0) {
- PRInt32 cipherBytesPart2 = -1;
+ int cipherBytesPart2 = -1;
rv = cwSpec->encode( cwSpec->encodeContext,
- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
&cipherBytesPart2, /* output and actual outLen */
p2Len, /* max outlen */
- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len,
+ wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
p2Len); /* input and inputLen*/
- PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
- if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
+ if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
@@ -2199,7 +2231,7 @@ ssl3_SendRecord( sslSocket * ss,
ssl_GetSpecReadLock(ss); /********************************/
if (nIn > 1 && ss->opt.cbcRandomIV &&
- ss->ssl3.cwSpec->version <= SSL_LIBRARY_VERSION_3_1_TLS &&
+ 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,
@@ -2211,6 +2243,10 @@ ssl3_SendRecord( sslSocket * ss,
}
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) {
@@ -8935,14 +8971,15 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
const ssl3BulkCipherDef *cipher_def;
ssl3CipherSpec * crSpec;
SECStatus rv;
- unsigned int hashBytes = MAX_MAC_LENGTH + 1;
+ unsigned int hashBytes = MAX_MAC_LENGTH + 1;
unsigned int padding_length;
PRBool isTLS;
- PRBool padIsBad = PR_FALSE;
+ PRBool padIsBad = PR_FALSE;
SSL3ContentType rType;
SSL3Opaque hash[MAX_MAC_LENGTH];
sslBuffer *plaintext;
sslBuffer temp_buf;
+ unsigned int ivLen = 0;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
@@ -8975,6 +9012,42 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
ssl_GetSpecReadLock(ss); /******************************************/
crSpec = ss->ssl3.crSpec;
+ cipher_def = crSpec->cipher_def;
+
+ if (cipher_def->type == type_block &&
+ crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states
+ * "The receiver decrypts the entire GenericBlockCipher structure and
+ * then discards the first cipher block corresponding to the IV
+ * component." Instead, we decrypt the first cipher block and then
+ * discard it before decrypting the rest.
+ */
+ SSL3Opaque iv[MAX_IV_LENGTH];
+ int decoded;
+
+ ivLen = cipher_def->iv_size;
+ if (ivLen < 8 || ivLen > sizeof(iv) || ivLen > cText->buf->len) {
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, IV length check failed",
+ SSL_GETPID(), ss->fd));
+ /* must not hold spec lock when calling SSL3_SendAlert. */
+ ssl_ReleaseSpecReadLock(ss);
+ ssl3_DecodeError(ss);
+ return SECFailure;
+ }
+
+ PRINT_BUF(80, (ss, "IV (ciphertext):", cText->buf->buf, ivLen));
+
+ rv = crSpec->decode(crSpec->decodeContext, iv, &decoded,
+ sizeof(iv), cText->buf->buf, ivLen);
+
+ PRINT_BUF(80, (ss, "IV (cleartext):", iv, ivLen));
+ if (rv != SECSuccess) {
+ /* All decryption failures must be treated like a bad record
+ * MAC; see RFC 5246 (TLS 1.2).
+ */
+ padIsBad = PR_TRUE;
+ }
+ }
/* If we will be decompressing the buffer we need to decrypt somewhere
* other than into databuf */
@@ -8999,12 +9072,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
}
}
- PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf, cText->buf->len));
+ PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen,
+ cText->buf->len - ivLen));
- cipher_def = crSpec->cipher_def;
isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0);
- if (isTLS && cText->buf->len > (MAX_FRAGMENT_LENGTH + 2048)) {
+ if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) {
ssl_ReleaseSpecReadLock(ss);
SSL3_SendAlert(ss, alert_fatal, record_overflow);
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
@@ -9014,7 +9087,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
/* decrypt from cText buf to plaintext. */
rv = crSpec->decode(
crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
- plaintext->space, cText->buf->buf, cText->buf->len);
+ plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
if (rv != SECSuccess) {
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index ac7171142..0fff5b2f0 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -490,6 +490,7 @@ typedef enum {
typedef enum { type_stream, type_block } CipherType;
+/* XXX Why is MAX_IV_LENGTH so big? */
#define MAX_IV_LENGTH 64
/*
@@ -1350,7 +1351,7 @@ extern PRBool ssl3_CanFalseStart(sslSocket *ss);
* runtime to determine which versions are supported by the version of libssl
* in use.
*/
-#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_0
+#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_1
/* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */
#define SSL3_ALL_VERSIONS_DISABLED(vrange) \
diff --git a/security/nss/lib/ssl/sslproto.h b/security/nss/lib/ssl/sslproto.h
index a11003f26..ab7a2b9b1 100644
--- a/security/nss/lib/ssl/sslproto.h
+++ b/security/nss/lib/ssl/sslproto.h
@@ -48,6 +48,7 @@
#define SSL_LIBRARY_VERSION_2 0x0002
#define SSL_LIBRARY_VERSION_3_0 0x0300
#define SSL_LIBRARY_VERSION_TLS_1_0 0x0301
+#define SSL_LIBRARY_VERSION_TLS_1_1 0x0302
/* deprecated old name */
#define SSL_LIBRARY_VERSION_3_1_TLS SSL_LIBRARY_VERSION_TLS_1_0