Thanks Robert for your reply. I will try your solution. 

For the reference, I'm attaching the back ported fix for the 3.12.5, with no 
warranties.

Regards,
Sergey

--- nss-3.12.5-orig/mozilla/security/nss/lib/ssl/ssl.h  Tue Jan 15 16:40:47 2013
+++ nss-3.12.5/mozilla/security/nss/lib/ssl/ssl.h       Wed Jan 16 17:22:43 2013
@@ -122,6 +122,33 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFi
                                           /* default: off                   */
                                          /* NOT YET IMPLEMENTED in 3.12.5  */
 
+/* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks
+ * on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting
+ * non-empty application_data records into two records; the first record has
+ * only the first byte of plaintext, and the second has the rest.
+ *
+ * This only prevents the attack in the sending direction; the connection may
+ * still be vulnerable to such attacks if the peer does not implement a similar
+ * countermeasure.
+ *
+ * This protection mechanism is on by default; the default can be overridden
+ * by the application setting the option SSL_CBC_RANDOM_IV to PR_FALSE.
+ *
+ * The per-record IV in TLS 1.1 and later adds one block of overhead per
+ * record, whereas this hack will add at least two blocks of overhead per
+ * record, so TLS 1.1+ will always be more efficient.
+ *
+ * Other implementations (e.g. some versions of OpenSSL, in some
+ * configurations) prevent the same attack by prepending an empty
+ * application_data record to every application_data record they send; we do
+ * not do that because some implementations cannot handle empty
+ * application_data records. Also, we only split application_data records and
+ * not other types of records, because some implementations will not accept
+ * fragmented records of some other types (e.g. some versions of NSS do not
+ * accept fragmented alerts).
+ */
+#define SSL_CBC_RANDOM_IV 23
+
 #ifdef SSL_DEPRECATED_FUNCTION 
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
--- nss-3.12.5-orig/mozilla/security/nss/lib/ssl/ssl3con.c      Tue Jan 15 
16:40:47 2013
+++ nss-3.12.5/mozilla/security/nss/lib/ssl/ssl3con.c   Wed Jan 16 15:12:16 2013
@@ -2018,23 +2018,20 @@ ssl3_ClientAuthTokenPresent(sslSessionID
 }
 
 static SECStatus
-ssl3_CompressMACEncryptRecord(sslSocket *        ss,
+ssl3_CompressMACEncryptRecord(ssl3CipherSpec *   cwSpec,
+                              PRBool             isServer,
                               SSL3ContentType    type,
                              const SSL3Opaque * pIn,
-                             PRUint32           contentLen)
+                             PRUint32           contentLen,
+                      sslBuffer *        wrBuf)
 {
-    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;
 
-    ssl_GetSpecReadLock(ss);   /********************************/
-
-    cwSpec = ss->ssl3.cwSpec;
     cipher_def = cwSpec->cipher_def;
 
     if (cwSpec->compress) {
@@ -2051,12 +2048,12 @@ ssl3_CompressMACEncryptRecord(sslSocket 
     /*
      * Add the MAC
      */
-    rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer),
+    rv = ssl3_ComputeRecordMAC( cwSpec, 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;
+       return SECFailure;
     }
     p1Len   = contentLen;
     p2Len   = macLen;
@@ -2109,7 +2106,7 @@ ssl3_CompressMACEncryptRecord(sslSocket 
        PORT_Assert(rv == SECSuccess && cipherBytes == p1Len);
        if (rv != SECSuccess || cipherBytes != p1Len) {
            PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
-           goto spec_locked_loser;
+           return SECFailure;
        }
     }
     if (p2Len > 0) {
@@ -2123,7 +2120,7 @@ ssl3_CompressMACEncryptRecord(sslSocket 
        PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
        if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
            PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
-           goto spec_locked_loser;
+           return SECFailure;
        }
        cipherBytes += cipherBytesPart2;
     }  
@@ -2138,13 +2135,7 @@ ssl3_CompressMACEncryptRecord(sslSocket 
     wrBuf->buf[3] = MSB(cipherBytes);
     wrBuf->buf[4] = LSB(cipherBytes);
 
-    ssl_ReleaseSpecReadLock(ss); /************************************/
-
     return SECSuccess;
-
-spec_locked_loser:
-    ssl_ReleaseSpecReadLock(ss);
-    return SECFailure;
 }
 
 /* Process the plain text before sending it.
@@ -2205,28 +2196,76 @@ ssl3_SendRecord(   sslSocket *        ss
 
     while (nIn > 0) {
        PRUint32  contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
+    unsigned int spaceNeeded;
+    unsigned int numRecords;
+
+    ssl_GetSpecReadLock(ss);    /********************************/
 
-       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 (nIn > 1 && ss->opt.cbcRandomIV &&
+       ss->ssl3.cwSpec->version <= SSL_LIBRARY_VERSION_3_1_TLS &&
+       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 (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, newSpace));
-               return SECFailure; /* sslBuffer_Grow set a memory error code. */
+                        SSL_GETPID(), ss->fd, spaceNeeded));
+               goto spec_locked_loser; /* sslBuffer_Grow set error code. */
            }
        }
 
-       rv = ssl3_CompressMACEncryptRecord( ss, type, pIn, contentLen);
+   if (numRecords == 2) {
+       sslBuffer secondRecord;
+
+       rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+                                          ss->sec.isServer, 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 = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+                                          ss->sec.isServer, 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 {
+       rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+                                          ss->sec.isServer, type, pIn,
+                                          contentLen, wrBuf);
+       if (rv == SECSuccess) {
+           PRINT_BUF(50, (ss, "send (encrypted) record data:",
+                          wrBuf->buf, wrBuf->len));
+       }
+   }
+
+spec_locked_loser:
+   ssl_ReleaseSpecReadLock(ss); /************************************/
+
        if (rv != SECSuccess)
            return SECFailure;
 
        pIn += contentLen;
        nIn -= contentLen;
        PORT_Assert( nIn >= 0 );
-
-       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,
--- nss-3.12.5-orig/mozilla/security/nss/lib/ssl/sslimpl.h      Tue Jan 15 
16:40:47 2013
+++ nss-3.12.5/mozilla/security/nss/lib/ssl/sslimpl.h   Wed Jan 16 15:12:23 2013
@@ -337,6 +337,8 @@ typedef struct sslOptionsStr {
     unsigned int enableDeflate          : 1;  /* 19 */
     unsigned int enableRenegotiation    : 2;  /* 20-21 */
     unsigned int requireSafeNegotiation : 1;  /* 22 */
+    unsigned int _enableFalseStart_notInUse : 1;  /* 23 */
+    unsigned int cbcRandomIV : 1;  /* 24 */
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
--- nss-3.12.5-orig/mozilla/security/nss/lib/ssl/sslsock.c      Tue Jan 15 
16:40:47 2013
+++ nss-3.12.5/mozilla/security/nss/lib/ssl/sslsock.c   Wed Jan 16 15:14:16 2013
@@ -183,6 +183,8 @@ static sslOptions ssl_defaults = {
     PR_FALSE,   /* enableDeflate      */
     0,          /* enableRenegotiation (default: never) */
     PR_FALSE,   /* requireSafeNegotiation */
+    PR_FALSE,   /* enableFalseStart - not in use   */
+    PR_TRUE     /* cbcRandomIV        */
 };
 
 sslSessionIDLookupFunc  ssl_sid_lookup;
@@ -720,6 +722,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
        ss->opt.requireSafeNegotiation = on;
        break;
 
+      case SSL_CBC_RANDOM_IV:
+    ss->opt.cbcRandomIV = on;
+    break;
+    
       default:
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        rv = SECFailure;
@@ -783,6 +789,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
                                   on = ss->opt.enableRenegotiation; break;
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ss->opt.requireSafeNegotiation; break;
+    case SSL_CBC_RANDOM_IV:       on = ss->opt.cbcRandomIV;        break;
 
     default:
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -833,6 +840,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBo
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ssl_defaults.requireSafeNegotiation; 
                                  break;
+    case SSL_CBC_RANDOM_IV:       on = ssl_defaults.cbcRandomIV;        break;
 
     default:
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -975,6 +983,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBo
       case SSL_REQUIRE_SAFE_NEGOTIATION:
        ssl_defaults.requireSafeNegotiation = on;
        break;
+
+      case SSL_CBC_RANDOM_IV:
+    ssl_defaults.cbcRandomIV = on;
+    break;
 
       default:
        PORT_SetError(SEC_ERROR_INVALID_ARGS);

On Tuesday, January 15, 2013 11:37:47 PM UTC+2, Robert Relyea wrote:
> On 01/13/2013 02:51 AM, Sergey Emantayev wrote:
> 
> > Hi all,
> 
> >
> 
> > We are using NSS 3.12.5 in our security project. I'm interested in applying 
> > the fix of CVE-2011-3389 in this version. Due to the project requirement we 
> > are obligated to use a FIPS certified NSS module so we cannot move to NSS 
> > 3.13 there this issue is originally fixed.
> 
> >
> 
> > Looking to the bug notes 
> > https://bugzilla.mozilla.org/show_bug.cgi?id=665814 I found two code 
> > patches:
> 
> > 1. patch to add empty application data records by Adam Langley 
> > https://bug665814.bugzilla.mozilla.org/attachment.cgi?id=541137
> 
> > 2. patch v11: Prevent chosen plaintext attacks on CBC mode, on by default 
> > by Brian Smith (:bsmith) 
> > https://bug665814.bugzilla.mozilla.org/attachment.cgi?id=563777
> 
> You can pick up NSS 3.13 while still using NSS 3.12.5 softoken. This is 
> 
> what Red Hat ships in RHEL (well actually we ship NSS-SOFTOKEN 3.12.9, 
> 
> which just got its FIPS cert last year, and in 6.4 we are shipping it 
> 
> with NSS 3.14).
> 
> 
> 
> That would be most reliable.
> 
> >
> 
> > Are both patches enough to back port the fix to 3.12.5 or if not even 
> > possible to any other 3.12.x version?
> 
> >
> 
> > Thanks&  regards,
> 
> > Sergey Emantayev

-- 
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto

Reply via email to