Merge commit 'b2eaac1' into dtls

* commit 'b2eaac1':
  Stop assuming chars are signed
  Add tests for CBC record splitting
  Fix tests that were failing with record splitting
  Allow disabling record splitting at runtime
  Add 1/n-1 record splitting
  Enhance doc on ssl_write()

Conflicts:
	include/polarssl/ssl.h
	programs/ssl/ssl_client2.c
	programs/ssl/ssl_server2.c
diff --git a/ChangeLog b/ChangeLog
index 3912037..f4551fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -38,6 +38,7 @@
    * Add compile-time option POLARSSL_X509_MAX_INTERMEDIATE_CA to limit the
      length of an X.509 verification chain.
    * Support for renegotiation can now be disabled at compile-time
+   * Support for 1/n-1 record splitting, a countermeasure against BEAST.
 
 Bugfix
    * Stack buffer overflow if ctr_drbg_update() is called with too large
diff --git a/include/polarssl/check_config.h b/include/polarssl/check_config.h
index 262ff44..d2c3643 100644
--- a/include/polarssl/check_config.h
+++ b/include/polarssl/check_config.h
@@ -303,6 +303,11 @@
 #error "POLARSSL_SSL_SESSION_TICKETS_C defined, but not all prerequisites"
 #endif
 
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) && \
+    !defined(POLARSSL_SSL_PROTO_SSL3) && !defined(POLARSSL_SSL_PROTO_TLS1)
+#error "POLARSSL_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
+#endif
+
 #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) && \
         !defined(POLARSSL_X509_CRT_PARSE_C)
 #error "POLARSSL_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index 860a40b..6d76883 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -887,6 +887,18 @@
 //#define POLARSSL_SSL_HW_RECORD_ACCEL
 
 /**
+ * \def POLARSSL_SSL_CBC_RECORD_SPLITTING
+ *
+ * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0.
+ *
+ * This is a countermeasure to the BEAST attack, which also minimizes the risk
+ * of interoperability issues compared to sending 0-length records.
+ *
+ * Comment this macro to disable 1/n-1 record splitting.
+ */
+#define POLARSSL_SSL_CBC_RECORD_SPLITTING
+
+/**
  * \def POLARSSL_SSL_DISABLE_RENEGOTIATION
  *
  * Disable support for TLS renegotiation.
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 8e0ba54..26110d8 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -265,6 +265,9 @@
 #define SSL_SESSION_TICKETS_DISABLED     0
 #define SSL_SESSION_TICKETS_ENABLED      1
 
+#define SSL_CBC_RECORD_SPLITTING_DISABLED   -1
+#define SSL_CBC_RECORD_SPLITTING_ENABLED     0
+
 /*
  * DTLS retransmission states, see RFC 6347 4.2.4
  *
@@ -943,6 +946,10 @@
 #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
     unsigned char mfl_code;     /*!< MaxFragmentLength chosen by us   */
 #endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+    char split_done;            /*!< flag for record splitting:
+                                     -1 disabled, 0 todo, 1 done      */
+#endif
 
     /*
      * PKI layer
@@ -1857,6 +1864,21 @@
 int ssl_set_truncated_hmac( ssl_context *ssl, int truncate );
 #endif /* POLARSSL_SSL_TRUNCATED_HMAC */
 
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+/**
+ * \brief          Enable / Disable 1/n-1 record splitting
+ *                 (Default: SSL_CBC_RECORD_SPLITTING_ENABLED)
+ *
+ * \note           Only affects SSLv3 and TLS 1.0, not higher versions.
+ *                 Does not affect non-CBC ciphersuites in any version.
+ *
+ * \param ssl      SSL context
+ * \param split    SSL_CBC_RECORD_SPLITTING_ENABLED or
+ *                 SSL_CBC_RECORD_SPLITTING_DISABLED
+ */
+void ssl_set_cbc_record_splitting( ssl_context *ssl, char split );
+#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */
+
 #if defined(POLARSSL_SSL_SESSION_TICKETS)
 /**
  * \brief          Enable / Disable session tickets
@@ -2147,11 +2169,13 @@
  *                 it must be called later with the *same* arguments,
  *                 until it returns a positive value.
  *
- * \note           When DTLS is in use, and a maximum fragment length was
- *                 either set with \c ssl_set_max_frag_len() or negotiated by
- *                 the peer, len must not not be greater than the maximum
- *                 fragment length, or POLARSSL_ERR_SSL_BAD_INPUT_DATA is
- *                 returned.
+ * \note           If the requested length is greater than the maximum
+ *                 fragment length (either the built-in limit or the one set
+ *                 or negotiated with the peer), then:
+ *                 - with TLS, less bytes than requested are written. (In
+ *                 order to write larger messages, this function should be
+ *                 called in a loop.)
+ *                 - with DTLS, POLARSSL_ERR_SSL_BAD_INPUT_DATA is returned.
  */
 int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len );
 
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e25e565..12ee22e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -5027,6 +5027,10 @@
     ssl->out_msgtype = 0;
     ssl->out_msglen = 0;
     ssl->out_left = 0;
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+    if( ssl->split_done != SSL_CBC_RECORD_SPLITTING_DISABLED )
+        ssl->split_done = 0;
+#endif
 
     ssl->transform_in = NULL;
     ssl->transform_out = NULL;
@@ -5697,6 +5701,13 @@
 }
 #endif /* POLARSSL_SSL_TRUNCATED_HMAC */
 
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+void ssl_set_cbc_record_splitting( ssl_context *ssl, char split )
+{
+    ssl->split_done = split;
+}
+#endif
+
 void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy )
 {
     ssl->allow_legacy_renegotiation = allow_legacy;
@@ -6309,7 +6320,11 @@
 /*
  * Send application data to be encrypted by the SSL layer
  */
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+static int ssl_write_real( ssl_context *ssl, const unsigned char *buf, size_t len )
+#else
 int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len )
+#endif
 {
     int ret;
 #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
@@ -6393,6 +6408,45 @@
 }
 
 /*
+ * Write application data, doing 1/n-1 splitting if necessary.
+ *
+ * With non-blocking I/O, ssl_write_real() may return WANT_WRITE,
+ * then the caller will call us again with the same arguments, so
+ * remember wether we already did the split or not.
+ */
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len )
+{
+    int ret;
+
+    if( ssl->split_done == SSL_CBC_RECORD_SPLITTING_DISABLED ||
+        len <= 1 ||
+        ssl->minor_ver > SSL_MINOR_VERSION_1 ||
+        cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc )
+                                != POLARSSL_MODE_CBC )
+    {
+        return( ssl_write_real( ssl, buf, len ) );
+    }
+
+    if( ssl->split_done == 0 )
+    {
+        ssl->split_done = 1;
+        if( ( ret = ssl_write_real( ssl, buf, 1 ) ) < 0 )
+            return( ret );
+    }
+
+    if( ssl->split_done == 1 )
+    {
+        ssl->split_done = 0;
+        if( ( ret = ssl_write_real( ssl, buf + 1, len - 1 ) ) < 0 )
+            return( ret );
+    }
+
+    return( ret + 1 );
+}
+#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */
+
+/*
  * Notify the peer that the connection is being closed
  */
 int ssl_close_notify( ssl_context *ssl )
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index b49a48e..0ddd802 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -93,6 +93,7 @@
 #define DFL_AUTH_MODE           SSL_VERIFY_REQUIRED
 #define DFL_MFL_CODE            SSL_MAX_FRAG_LEN_NONE
 #define DFL_TRUNC_HMAC          0
+#define DFL_RECSPLIT            -1
 #define DFL_RECONNECT           0
 #define DFL_RECO_DELAY          0
 #define DFL_TICKETS             SSL_SESSION_TICKETS_ENABLED
@@ -138,6 +139,7 @@
     int auth_mode;              /* verify mode for connection               */
     unsigned char mfl_code;     /* code for maximum fragment length         */
     int trunc_hmac;             /* negotiate truncated hmac or not          */
+    int recsplit;               /* enable record splitting?                 */
     int reconnect;              /* attempt to resume session                */
     int reco_delay;             /* delay in seconds before resuming session */
     int tickets;                /* enable / disable session tickets         */
@@ -285,6 +287,13 @@
 #define USAGE_MAX_FRAG_LEN ""
 #endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */
 
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+#define USAGE_RECSPLIT \
+    "    recplit=%%d          default: (library default)\n"
+#else
+#define USAGE_RECSPLIT
+#endif
+
 #if defined(POLARSSL_TIMING_C)
 #define USAGE_TIME \
     "    reco_delay=%%d       default: 0 seconds\n"
@@ -373,6 +382,7 @@
     USAGE_FALLBACK                                          \
     USAGE_EMS                                               \
     USAGE_ETM                                               \
+    USAGE_RECSPLIT                                          \
     "\n"                                                    \
     "    min_version=%%s      default: \"\" (ssl3)\n"       \
     "    max_version=%%s      default: \"\" (tls1_2)\n"     \
@@ -471,6 +481,7 @@
     opt.auth_mode           = DFL_AUTH_MODE;
     opt.mfl_code            = DFL_MFL_CODE;
     opt.trunc_hmac          = DFL_TRUNC_HMAC;
+    opt.recsplit            = DFL_RECSPLIT;
     opt.reconnect           = DFL_RECONNECT;
     opt.reco_delay          = DFL_RECO_DELAY;
     opt.tickets             = DFL_TICKETS;
@@ -743,6 +754,12 @@
             if( opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min )
                 goto usage;
         }
+        else if( strcmp( p, "recsplit" ) == 0 )
+        {
+            opt.recsplit = atoi( q );
+            if( opt.recsplit < 0 || opt.recsplit > 1 )
+                goto usage;
+        }
         else
             goto usage;
     }
@@ -1058,6 +1075,13 @@
         ssl_set_encrypt_then_mac( &ssl, opt.etm );
 #endif
 
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+    if( opt.recsplit != DFL_RECSPLIT )
+        ssl_set_cbc_record_splitting( &ssl, opt.recsplit
+                                    ? SSL_CBC_RECORD_SPLITTING_ENABLED
+                                    : SSL_CBC_RECORD_SPLITTING_DISABLED );
+#endif
+
 #if defined(POLARSSL_SSL_ALPN)
     if( opt.alpn_string != NULL )
         if( ( ret = ssl_set_alpn_protocols( &ssl, alpn_list ) ) != 0 )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 1f9e97f..f2beaf1 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -192,14 +192,14 @@
     char *sni;                  /* string describing sni information        */
     const char *alpn_string;    /* ALPN supported protocols                 */
     const char *dhm_file;       /* the file with the DH parameters          */
+    int extended_ms;            /* allow negotiation of extended MS?        */
+    int etm;                    /* allow negotiation of encrypt-then-MAC?   */
     int transport;              /* TLS or DTLS?                             */
     int cookies;                /* Use cookies for DTLS? -1 to break them   */
     int anti_replay;            /* Use anti-replay for DTLS? -1 for default */
     uint32_t hs_to_min;         /* Initial value of DTLS handshake timer    */
     uint32_t hs_to_max;         /* Max value of DTLS handshake timer        */
     int badmac_limit;           /* Limit of records with bad MAC            */
-    char extended_ms;           /* allow negotiation of extended MS?        */
-    char etm;                   /* allow negotiation of encrypt-then-MAC?   */
 } opt;
 
 static void my_debug( void *ctx, int level, const char *str )
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 2e6e1fd..3099adc 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -791,6 +791,62 @@
             -s "received FALLBACK_SCSV" \
             -S "inapropriate fallback"
 
+# Tests for CBC 1/n-1 record splitting
+
+run_test    "CBC Record splitting: TLS 1.2, no splitting" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \
+             request_size=123 force_version=tls1_2" \
+            0 \
+            -s "Read from client: 123 bytes read" \
+            -S "Read from client: 1 bytes read" \
+            -S "122 bytes read"
+
+run_test    "CBC Record splitting: TLS 1.1, no splitting" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \
+             request_size=123 force_version=tls1_1" \
+            0 \
+            -s "Read from client: 123 bytes read" \
+            -S "Read from client: 1 bytes read" \
+            -S "122 bytes read"
+
+run_test    "CBC Record splitting: TLS 1.0, splitting" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \
+             request_size=123 force_version=tls1" \
+            0 \
+            -S "Read from client: 123 bytes read" \
+            -s "Read from client: 1 bytes read" \
+            -s "122 bytes read"
+
+run_test    "CBC Record splitting: SSLv3, splitting" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \
+             request_size=123 force_version=ssl3" \
+            0 \
+            -S "Read from client: 123 bytes read" \
+            -s "Read from client: 1 bytes read" \
+            -s "122 bytes read"
+
+run_test    "CBC Record splitting: TLS 1.0 RC4, no splitting" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \
+             request_size=123 force_version=tls1" \
+            0 \
+            -s "Read from client: 123 bytes read" \
+            -S "Read from client: 1 bytes read" \
+            -S "122 bytes read"
+
+run_test    "CBC Record splitting: TLS 1.0, splitting disabled" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \
+             request_size=123 force_version=tls1 recsplit=0" \
+            0 \
+            -s "Read from client: 123 bytes read" \
+            -S "Read from client: 1 bytes read" \
+            -S "122 bytes read"
+
 # Tests for Session Tickets
 
 run_test    "Session resume using tickets: basic" \
@@ -2283,7 +2339,8 @@
 
 run_test    "Small packet TLS 1.2 BlockCipher larger MAC" \
             "$P_SRV" \
-            "$P_CLI request_size=1 force_version=tls1_2 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384" \
+            "$P_CLI request_size=1 force_version=tls1_2 \
+             force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384" \
             0 \
             -s "Read from client: 1 bytes read"
 
@@ -2328,7 +2385,7 @@
 
 run_test    "Large packet SSLv3 BlockCipher" \
             "$P_SRV" \
-            "$P_CLI request_size=16384 force_version=ssl3 \
+            "$P_CLI request_size=16384 force_version=ssl3 recsplit=0 \
              force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
             0 \
             -s "Read from client: 16384 bytes read"
@@ -2342,14 +2399,14 @@
 
 run_test    "Large packet TLS 1.0 BlockCipher" \
             "$P_SRV" \
-            "$P_CLI request_size=16384 force_version=tls1 \
+            "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \
              force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
             0 \
             -s "Read from client: 16384 bytes read"
 
 run_test    "Large packet TLS 1.0 BlockCipher truncated MAC" \
             "$P_SRV" \
-            "$P_CLI request_size=16384 force_version=tls1 \
+            "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \
              force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA \
              trunc_hmac=1" \
             0 \
@@ -2402,7 +2459,8 @@
 
 run_test    "Large packet TLS 1.2 BlockCipher larger MAC" \
             "$P_SRV" \
-            "$P_CLI request_size=16384 force_version=tls1_2 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384" \
+            "$P_CLI request_size=16384 force_version=tls1_2 \
+             force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384" \
             0 \
             -s "Read from client: 16384 bytes read"