Test SSL_set_max_send_fragment.

This gives coverage over needing to fragment something over multiple
records.

Change-Id: I2373613608ef669358d48f4e12f68577fa5a40dc
Reviewed-on: https://boringssl-review.googlesource.com/13101
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 900e4f6..bbbebe7 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1633,6 +1633,9 @@
   if (is_resume && config->retain_only_sha256_client_cert_resume) {
     SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
   }
+  if (config->max_send_fragment > 0) {
+    SSL_set_max_send_fragment(ssl.get(), config->max_send_fragment);
+  }
 
   int sock = Connect(config->port);
   if (sock == -1) {
@@ -1796,12 +1799,15 @@
     }
     if (!config->shim_shuts_down) {
       for (;;) {
-        static const size_t kBufLen = 16384;
-        std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufLen]);
-
         // Read only 512 bytes at a time in TLS to ensure records may be
         // returned in multiple reads.
-        int n = DoRead(ssl.get(), buf.get(), config->is_dtls ? kBufLen : 512);
+        size_t read_size = config->is_dtls ? 16384 : 512;
+        if (config->read_size > 0) {
+          read_size = config->read_size;
+        }
+        std::unique_ptr<uint8_t[]> buf(new uint8_t[read_size]);
+
+        int n = DoRead(ssl.get(), buf.get(), read_size);
         int err = SSL_get_error(ssl.get(), n);
         if (err == SSL_ERROR_ZERO_RETURN ||
             (n == 0 && err == SSL_ERROR_SYSCALL)) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 96bc39a..3afd73f 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1253,6 +1253,10 @@
 	// formats to send in ClientHello or ServerHello. If set to a non-nil
 	// empty slice, no extension will be sent.
 	SendSupportedPointFormats []byte
+
+	// MaxReceivePlaintext, if non-zero, is the maximum plaintext record
+	// length accepted from the peer.
+	MaxReceivePlaintext int
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index ee342fa..3cbd496 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -876,7 +876,11 @@
 		return err
 	}
 	data := b.data[b.off:]
-	if len(data) > maxPlaintext {
+	max := maxPlaintext
+	if c.config.Bugs.MaxReceivePlaintext != 0 {
+		max = c.config.Bugs.MaxReceivePlaintext
+	}
+	if len(data) > max {
 		err := c.sendAlert(alertRecordOverflow)
 		c.in.freeBlock(b)
 		return c.in.setErrorLocked(err)
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index dee1bb9..3a884bc 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2401,6 +2401,42 @@
 				},
 			},
 		},
+		{
+			// Test the server so there is a large certificate as
+			// well as application data.
+			testType: serverTest,
+			name:     "MaxSendFragment",
+			config: Config{
+				Bugs: ProtocolBugs{
+					MaxReceivePlaintext: 512,
+				},
+			},
+			messageLen: 1024,
+			flags: []string{
+				"-max-send-fragment", "512",
+				"-read-size", "1024",
+			},
+		},
+		{
+			// Test the server so there is a large certificate as
+			// well as application data.
+			testType: serverTest,
+			name:     "MaxSendFragment-TooLarge",
+			config: Config{
+				Bugs: ProtocolBugs{
+					// Ensure that some of the records are
+					// 512.
+					MaxReceivePlaintext: 511,
+				},
+			},
+			messageLen: 1024,
+			flags: []string{
+				"-max-send-fragment", "512",
+				"-read-size", "1024",
+			},
+			shouldFail:         true,
+			expectedLocalError: "local error: record overflow",
+		},
 	}
 	testCases = append(testCases, basicTests...)
 
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 10a86db..5bc9544 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -176,6 +176,8 @@
   { "-expect-cipher-aes", &TestConfig::expect_cipher_aes },
   { "-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes },
   { "-resumption-delay", &TestConfig::resumption_delay },
+  { "-max-send-fragment", &TestConfig::max_send_fragment },
+  { "-read-size", &TestConfig::read_size },
 };
 
 const Flag<std::vector<int>> kIntVectorFlags[] = {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index ff91cef..7cf0a6f 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -129,6 +129,8 @@
   bool read_with_unfinished_write = false;
   bool expect_secure_renegotiation = false;
   bool expect_no_secure_renegotiation = false;
+  int max_send_fragment = 0;
+  int read_size = 0;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);