Add small_records.patch and handshake_cutthrough.patch.
See patches/README for additional details.
diff --git a/apps/s_client.c b/apps/s_client.c
index 4974f5f..f73ed2d 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -248,6 +248,7 @@
BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
BIO_printf(bio_err," -status - request certificate status from server\n");
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
+ BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n");
#endif
}
@@ -304,6 +305,7 @@
EVP_PKEY *key = NULL;
char *CApath=NULL,*CAfile=NULL,*cipher=NULL;
int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0;
+ int cutthrough=0;
int crlf=0;
int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending;
SSL_CTX *ctx=NULL;
@@ -533,6 +535,8 @@
else if (strcmp(*argv,"-no_ticket") == 0)
{ off|=SSL_OP_NO_TICKET; }
#endif
+ else if (strcmp(*argv,"-cutthrough") == 0)
+ cutthrough=1;
else if (strcmp(*argv,"-serverpref") == 0)
off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
else if (strcmp(*argv,"-cipher") == 0)
@@ -714,6 +718,15 @@
*/
if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
+ /* Enable handshake cutthrough for client connections using
+ * strong ciphers. */
+ if (cutthrough)
+ {
+ int ssl_mode = SSL_CTX_get_mode(ctx);
+ ssl_mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH;
+ SSL_CTX_set_mode(ctx, ssl_mode);
+ }
+
if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
if (cipher != NULL)
if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
diff --git a/import_openssl.sh b/import_openssl.sh
index dda6bce..33e7244 100755
--- a/import_openssl.sh
+++ b/import_openssl.sh
@@ -57,6 +57,11 @@
tar -zxf $OPENSSL_SOURCE
cd openssl-$OPENSSL_VERSION
+# Apply appropriate patches
+for i in $OPENSSL_PATCHES; do
+ patch -p1 < ../patches/$i
+done
+
./Configure $CONFIGURE_ARGS
# TODO(): Fixup android-config.mk
@@ -64,9 +69,6 @@
cp -f LICENSE ../NOTICE
touch ../MODULE_LICENSE_BSD_LIKE
-# Prune unnecessary sources
-rm -rf $UNNEEDED_SOURCES
-
# Avoid checking in symlinks
for i in `find include/openssl -type l`; do
target=`readlink $i`
@@ -76,16 +78,14 @@
fi
done
-# Apply appropriate patches
-for i in $OPENSSL_PATCHES; do
- patch -p1 < ../patches/$i
-done
-
# Copy Makefiles
cp ../patches/apps_Android.mk apps/Android.mk
cp ../patches/crypto_Android.mk crypto/Android.mk
cp ../patches/ssl_Android.mk ssl/Android.mk
+# Prune unnecessary sources
+rm -rf $UNNEEDED_SOURCES
+
cd ..
cp -af openssl-$OPENSSL_VERSION/include .
rm -rf apps/
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ff8a128..0e0bc6e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -554,7 +554,13 @@
#define SSL_MODE_AUTO_RETRY 0x00000004L
/* Don't attempt to automatically build certificate chain */
#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
-
+/* Use small read and write buffers: (a) lazy allocate read buffers for
+ * large incoming records, and (b) limit the size of outgoing records. */
+#define SSL_MODE_SMALL_BUFFERS 0x00000010L
+/* When set, clients may send application data before receipt of CCS
+ * and Finished. This mode enables full-handshakes to 'complete' in
+ * one RTT. */
+#define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000020L
/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
* they cannot be used to clear bits. */
@@ -1095,10 +1101,12 @@
/* Is the SSL_connection established? */
#define SSL_get_state(a) SSL_state(a)
#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
-#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
+#define SSL_in_init(a) ((SSL_state(a)&SSL_ST_INIT) && \
+ !SSL_cutthrough_complete(a))
#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
+int SSL_cutthrough_complete(const SSL *s);
/* The following 2 states are kept in ssl->rstate when reads fail,
* you should not need these */
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 4b1e2e9..803e13a 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -253,6 +253,9 @@
#define SSL3_RT_MAX_EXTRA (16384)
#endif
+/* Default buffer length used for writen records. Thus a generated record
+ * will contain plaintext no larger than this value. */
+#define SSL3_RT_DEFAULT_PLAIN_LENGTH 2048
#define SSL3_RT_MAX_PLAIN_LENGTH 16384
#ifdef OPENSSL_NO_COMP
#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
@@ -260,6 +263,12 @@
#define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH)
#endif
#define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
+/* Extra space for empty fragment, headers, MAC, and padding. */
+#define SSL3_RT_DEFAULT_WRITE_OVERHEAD 256
+#define SSL3_RT_DEFAULT_PACKET_SIZE 4096 - SSL3_RT_DEFAULT_WRITE_OVERHEAD
+#if SSL3_RT_DEFAULT_PLAIN_LENGTH + SSL3_RT_DEFAULT_WRITE_OVERHEAD > SSL3_RT_DEFAULT_PACKET_SIZE
+#error "Insufficient space allocated for write buffers."
+#endif
#define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
#define SSL3_RT_MAX_DATA_SIZE (1024*1024)
@@ -447,6 +456,7 @@
/*client */
/* extra state */
#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
+#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT)
/* write to server */
#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
diff --git a/openssl.config b/openssl.config
index 977aa56..72b709a 100644
--- a/openssl.config
+++ b/openssl.config
@@ -4,20 +4,22 @@
-DL_ENDIAN"
UNNEEDED_SOURCES="\
- MacOS Netware VMS apps/demoCA apps/set bugs certs crypto/bf crypto/cast \
- crypto/cms crypto/idea crypto/md2 crypto/rc5 crypto/seed demos doc \
+ MacOS Netware VMS apps/demoCA apps/set bugs certs crypto/bf crypto/cast \
+ crypto/cms crypto/idea crypto/md2 crypto/rc5 crypto/seed demos doc \
engines ms os2 perl shlib test times tools util "
UNNEEDED_SOURCES+="\
- CHANGES CHANGES.SSLeay ChangeLog.0_9_7-stable_not-in-head \
- ChangeLog.0_9_7-stable_not-in-head_FIPS Configure FAQ INSTALL \
- INSTALL.DJGPP INSTALL.MacOS INSTALL.NW INSTALL.OS2 INSTALL.VMS \
- INSTALL.W32 INSTALL.W64 INSTALL.WCE LICENSE Makefile Makefile.bak \
- Makefile.org Makefile.shared NEWS PROBLEMS README README.ASN1 \
- README.ENGINE apps/CA.pl.bak config crypto/opensslconf.h.bak \
+ CHANGES CHANGES.SSLeay ChangeLog.0_9_7-stable_not-in-head \
+ ChangeLog.0_9_7-stable_not-in-head_FIPS Configure FAQ INSTALL \
+ INSTALL.DJGPP INSTALL.MacOS INSTALL.NW INSTALL.OS2 INSTALL.VMS \
+ INSTALL.W32 INSTALL.W64 INSTALL.WCE LICENSE Makefile Makefile.bak \
+ Makefile.org Makefile.shared NEWS PROBLEMS README README.ASN1 \
+ README.ENGINE apps/CA.pl.bak config crypto/opensslconf.h.bak \
install.com makevms.com openssl.doxy openssl.spec"
OPENSSL_PATCHES="\
- progs.patch \
- arm-asm.patch \
- openssl_defs.patch"
+ progs.patch \
+ arm-asm.patch \
+ openssl_defs.patch \
+ small_records.patch \
+ handshake_cutthrough.patch"
diff --git a/patches/README b/patches/README
new file mode 100644
index 0000000..6ec6e6b
--- /dev/null
+++ b/patches/README
@@ -0,0 +1,33 @@
+progs.patch:
+
+Fixup sources under the apps/ directory that are not built under the android environment.
+
+
+arm-asm.patch.patch:
+
+ARM assembly routines (AES, BN, SHA1, SHA256, SHA512)
+
+
+openssl_defs.patch:
+
+Fixup missing #defines.
+
+
+small_records.patch:
+
+Reduce OpenSSL memory consumption.
+SSL records may be as large as 16K, but are typically < 2K. In
+addition, a historic bug in Windows allowed records to be as large
+32K. OpenSSL statically allocates read and write buffers (34K and
+18K respectively) used for processing records.
+With this patch, OpenSSL statically allocates 4K + 4K buffers, with
+the option of dynamically growing buffers to 34K + 4K, which is a
+saving of 44K per connection for the typical case.
+
+
+handshake_cutthrough.patch
+
+Enables SSL3+ clients to send application data immediately following the
+Finished message even when negotiating full-handshakes. With this patch,
+clients can negotiate SSL connections in 1-RTT even when performing
+full-handshakes.
diff --git a/patches/handshake_cutthrough.patch b/patches/handshake_cutthrough.patch
new file mode 100644
index 0000000..16538a1
--- /dev/null
+++ b/patches/handshake_cutthrough.patch
@@ -0,0 +1,227 @@
+diff -uarp openssl-0.9.8k.orig/apps/s_client.c openssl-0.9.8k/apps/s_client.c
+--- openssl-0.9.8k.orig/apps/s_client.c 2008-12-20 09:04:08.000000000 -0800
++++ openssl-0.9.8k/apps/s_client.c 2009-10-01 10:32:25.000000000 -0700
+@@ -248,6 +248,7 @@ static void sc_usage(void)
+ BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
+ BIO_printf(bio_err," -status - request certificate status from server\n");
+ BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
++ BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n");
+ #endif
+ }
+
+@@ -304,6 +305,7 @@ int MAIN(int argc, char **argv)
+ EVP_PKEY *key = NULL;
+ char *CApath=NULL,*CAfile=NULL,*cipher=NULL;
+ int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0;
++ int cutthrough=0;
+ int crlf=0;
+ int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending;
+ SSL_CTX *ctx=NULL;
+@@ -533,6 +535,8 @@ int MAIN(int argc, char **argv)
+ else if (strcmp(*argv,"-no_ticket") == 0)
+ { off|=SSL_OP_NO_TICKET; }
+ #endif
++ else if (strcmp(*argv,"-cutthrough") == 0)
++ cutthrough=1;
+ else if (strcmp(*argv,"-serverpref") == 0)
+ off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
+ else if (strcmp(*argv,"-cipher") == 0)
+@@ -714,6 +718,15 @@ bad:
+ */
+ if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
+
++ /* Enable handshake cutthrough for client connections using
++ * strong ciphers. */
++ if (cutthrough)
++ {
++ int ssl_mode = SSL_CTX_get_mode(ctx);
++ ssl_mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH;
++ SSL_CTX_set_mode(ctx, ssl_mode);
++ }
++
+ if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
+ if (cipher != NULL)
+ if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
+diff -uarp openssl-0.9.8k.orig/include/openssl/ssl3.h openssl-0.9.8k/include/openssl/ssl3.h
+--- openssl-0.9.8k.orig/include/openssl/ssl3.h 2009-10-01 10:32:15.000000000 -0700
++++ openssl-0.9.8k/include/openssl/ssl3.h 2009-10-01 10:32:25.000000000 -0700
+@@ -456,6 +456,7 @@ typedef struct ssl3_state_st
+ /*client */
+ /* extra state */
+ #define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
++#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT)
+ /* write to server */
+ #define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
+ #define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
+diff -uarp openssl-0.9.8k.orig/ssl/s3_clnt.c openssl-0.9.8k/ssl/s3_clnt.c
+--- openssl-0.9.8k.orig/ssl/s3_clnt.c 2009-02-14 13:50:14.000000000 -0800
++++ openssl-0.9.8k/ssl/s3_clnt.c 2009-10-01 10:32:25.000000000 -0700
+@@ -454,14 +454,20 @@ int ssl3_connect(SSL *s)
+ }
+ else
+ {
+-#ifndef OPENSSL_NO_TLSEXT
+- /* Allow NewSessionTicket if ticket expected */
+- if (s->tlsext_ticket_expected)
+- s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
++ if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && SSL_get_cipher_bits(s, NULL) >= 128)
++ {
++ s->s3->tmp.next_state=SSL3_ST_CUTTHROUGH_COMPLETE;
++ }
+ else
++ {
++#ifndef OPENSSL_NO_TLSEXT
++ /* Allow NewSessionTicket if ticket expected */
++ if (s->tlsext_ticket_expected)
++ s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
++ else
+ #endif
+-
+- s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
++ s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
++ }
+ }
+ s->init_num=0;
+ break;
+@@ -512,6 +518,22 @@ int ssl3_connect(SSL *s)
+ s->state=s->s3->tmp.next_state;
+ break;
+
++ case SSL3_ST_CUTTHROUGH_COMPLETE:
++#ifndef OPENSSL_NO_TLSEXT
++ /* Allow NewSessionTicket if ticket expected */
++ if (s->tlsext_ticket_expected)
++ s->state=SSL3_ST_CR_SESSION_TICKET_A;
++ else
++#endif
++ s->state=SSL3_ST_CR_FINISHED_A;
++
++ /* Allow application writes to go through. Note that SSL3_FLAGS_DELAY_CLIENT_FINISHED
++ * is not supported on cutthrough connections (just for simplicity) */
++ ssl_free_wbio_buffer(s);
++ ret = 1;
++ goto end;
++ /* break; */
++
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+diff -uarp openssl-0.9.8k.orig/ssl/ssl.h openssl-0.9.8k/ssl/ssl.h
+--- openssl-0.9.8k.orig/ssl/ssl.h 2009-10-01 10:32:15.000000000 -0700
++++ openssl-0.9.8k/ssl/ssl.h 2009-10-01 10:32:25.000000000 -0700
+@@ -557,6 +557,10 @@ typedef struct ssl_session_st
+ /* Use small read and write buffers: (a) lazy allocate read buffers for
+ * large incoming records, and (b) limit the size of outgoing records. */
+ #define SSL_MODE_SMALL_BUFFERS 0x00000010L
++/* When set, clients may send application data before receipt of CCS
++ * and Finished. This mode enables full-handshakes to 'complete' in
++ * one RTT. */
++#define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000020L
+
+ /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
+ * they cannot be used to clear bits. */
+@@ -1097,10 +1101,12 @@ extern "C" {
+ /* Is the SSL_connection established? */
+ #define SSL_get_state(a) SSL_state(a)
+ #define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
+-#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
++#define SSL_in_init(a) ((SSL_state(a)&SSL_ST_INIT) && \
++ !SSL_cutthrough_complete(a))
+ #define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
+ #define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
+ #define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
++int SSL_cutthrough_complete(const SSL *s);
+
+ /* The following 2 states are kept in ssl->rstate when reads fail,
+ * you should not need these */
+Only in openssl-0.9.8k/ssl: ssl.h.orig
+diff -uarp openssl-0.9.8k.orig/ssl/ssl3.h openssl-0.9.8k/ssl/ssl3.h
+--- openssl-0.9.8k.orig/ssl/ssl3.h 2009-10-01 10:32:15.000000000 -0700
++++ openssl-0.9.8k/ssl/ssl3.h 2009-10-01 10:32:25.000000000 -0700
+@@ -456,6 +456,7 @@ typedef struct ssl3_state_st
+ /*client */
+ /* extra state */
+ #define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
++#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT)
+ /* write to server */
+ #define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
+ #define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
+diff -uarp openssl-0.9.8k.orig/ssl/ssl_lib.c openssl-0.9.8k/ssl/ssl_lib.c
+--- openssl-0.9.8k.orig/ssl/ssl_lib.c 2009-02-23 08:02:47.000000000 -0800
++++ openssl-0.9.8k/ssl/ssl_lib.c 2009-10-01 10:32:25.000000000 -0700
+@@ -2696,7 +2696,17 @@ void SSL_set_msg_callback(SSL *ssl, void
+ SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
+ }
+
+-
++int SSL_cutthrough_complete(const SSL *s)
++ {
++ return (!s->server && /* cutthrough only applies to clients */
++ !s->hit && /* full-handshake */
++ s->version >= SSL3_VERSION &&
++ s->s3->in_read_app_data == 0 && /* cutthrough only applies to write() */
++ (SSL_get_mode((SSL*)s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && /* cutthrough enabled */
++ SSL_get_cipher_bits(s, NULL) >= 128 && /* strong cipher choosen */
++ (s->state == SSL3_ST_CR_SESSION_TICKET_A || /* ready to write app-data*/
++ s->state == SSL3_ST_CR_FINISHED_A));
++ }
+
+ #if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
+ #include "../crypto/bio/bss_file.c"
+Only in openssl-0.9.8k/ssl: ssl_lib.c.orig
+diff -uarp openssl-0.9.8k.orig/test/ssltest.c openssl-0.9.8k/test/ssltest.c
+--- openssl-0.9.8k.orig/test/ssltest.c 2009-10-01 10:32:15.000000000 -0700
++++ openssl-0.9.8k/test/ssltest.c 2009-10-01 10:32:25.000000000 -0700
+@@ -279,6 +279,7 @@ static void sv_usage(void)
+ fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+ fprintf(stderr," -c_small_records - enable client side use of small SSL record buffers\n");
+ fprintf(stderr," -s_small_records - enable server side use of small SSL record buffers\n");
++ fprintf(stderr," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n");
+ }
+
+ static void print_details(SSL *c_ssl, const char *prefix)
+@@ -436,6 +437,7 @@ int main(int argc, char *argv[])
+ int ssl_mode = 0;
+ int c_small_records=0;
+ int s_small_records=0;
++ int cutthrough = 0;
+
+ verbose = 0;
+ debug = 0;
+@@ -632,6 +634,10 @@ int main(int argc, char *argv[])
+ {
+ s_small_records = 1;
+ }
++ else if (strcmp(*argv, "-cutthrough") == 0)
++ {
++ cutthrough = 1;
++ }
+ else
+ {
+ fprintf(stderr,"unknown option %s\n",*argv);
+@@ -782,6 +788,13 @@ bad:
+ ssl_mode |= SSL_MODE_SMALL_BUFFERS;
+ SSL_CTX_set_mode(s_ctx, ssl_mode);
+ }
++ ssl_mode = 0;
++ if (cutthrough)
++ {
++ ssl_mode = SSL_CTX_get_mode(c_ctx);
++ ssl_mode = SSL_MODE_HANDSHAKE_CUTTHROUGH;
++ SSL_CTX_set_mode(c_ctx, ssl_mode);
++ }
+
+ #ifndef OPENSSL_NO_DH
+ if (!no_dhe)
+diff -uarp openssl-0.9.8k.orig/test/testssl openssl-0.9.8k/test/testssl
+--- openssl-0.9.8k.orig/test/testssl 2009-10-01 10:32:15.000000000 -0700
++++ openssl-0.9.8k/test/testssl 2009-10-01 10:32:25.000000000 -0700
+@@ -79,6 +79,8 @@ $ssltest -server_auth -client_auth -s_sm
+ echo test sslv2/sslv3 with both client and server authentication and small client and server buffers
+ $ssltest -server_auth -client_auth -c_small_records -s_small_records $CA $extra || exit 1
+
++echo test sslv2/sslv3 with both client and server authentication and handshake cutthrough
++$ssltest -server_auth -client_auth -cutthrough $CA $extra || exit 1
+
+ echo test sslv2 via BIO pair
+ $ssltest -bio_pair -ssl2 $extra || exit 1
diff --git a/patches/small_records.patch b/patches/small_records.patch
new file mode 100644
index 0000000..42158e0
--- /dev/null
+++ b/patches/small_records.patch
@@ -0,0 +1,315 @@
+diff -uarp openssl-0.9.8j.orig/ssl/d1_pkt.c openssl-0.9.8j/ssl/d1_pkt.c
+--- openssl-0.9.8j.orig/ssl/d1_pkt.c 2008-10-12 23:43:06.000000000 -0700
++++ openssl-0.9.8j/ssl/d1_pkt.c 2009-04-21 11:50:28.490911000 -0700
+@@ -561,6 +561,21 @@ again:
+ goto f_err;
+ }
+
++ /* If we receive a valid record larger than the current buffer size,
++ * allocate some memory for it.
++ */
++ if (rr->length > s->s3->rbuf.len - DTLS1_RT_HEADER_LENGTH)
++ {
++ if ((p=OPENSSL_realloc(s->s3->rbuf.buf, rr->length + DTLS1_RT_HEADER_LENGTH))==NULL)
++ {
++ SSLerr(SSL_F_DTLS1_GET_RECORD,ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++ s->s3->rbuf.buf=p;
++ s->s3->rbuf.len=rr->length + DTLS1_RT_HEADER_LENGTH;
++ s->packet= &(s->s3->rbuf.buf[0]);
++ }
++
+ s->client_version = version;
+ /* now s->rstate == SSL_ST_READ_BODY */
+ }
+@@ -1226,6 +1241,7 @@ int dtls1_write_bytes(SSL *s, int type,
+ unsigned int tot,n,nw;
+ int i;
+ unsigned int mtu;
++ unsigned int max_mtu;
+
+ s->rwstate=SSL_NOTHING;
+ tot=s->s3->wnum;
+@@ -1240,8 +1256,17 @@ int dtls1_write_bytes(SSL *s, int type,
+ #endif
+ mtu = s->d1->mtu;
+
+- if (mtu > SSL3_RT_MAX_PLAIN_LENGTH)
+- mtu = SSL3_RT_MAX_PLAIN_LENGTH;
++ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS))
++ {
++ max_mtu = SSL3_RT_MAX_PLAIN_LENGTH;
++ }
++ else
++ {
++ max_mtu = SSL3_RT_DEFAULT_PLAIN_LENGTH;
++ }
++
++ if (mtu > max_mtu)
++ mtu = max_mtu;
+
+ if (n > mtu)
+ nw=mtu;
+@@ -1327,7 +1352,9 @@ int do_dtls1_write(SSL *s, int type, con
+ if (prefix_len <= 0)
+ goto err;
+
+- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
++ if (s->s3->wbuf.len < (size_t)prefix_len +
++ ((SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) ? SSL3_RT_DEFAULT_PACKET_SIZE :
++ SSL3_RT_MAX_PACKET_SIZE))
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR);
+diff -uarp openssl-0.9.8j.orig/ssl/s23_srvr.c openssl-0.9.8j/ssl/s23_srvr.c
+--- openssl-0.9.8j.orig/ssl/s23_srvr.c 2008-06-16 09:56:41.000000000 -0700
++++ openssl-0.9.8j/ssl/s23_srvr.c 2009-04-21 11:28:58.540698000 -0700
+@@ -405,8 +405,13 @@ int ssl23_get_client_hello(SSL *s)
+ v[0] = p[3]; /* == SSL3_VERSION_MAJOR */
+ v[1] = p[4];
+
++/* The SSL2 protocol allows n to be larger, just pick
++ * a reasonable buffer size. */
++#if SSL3_RT_DEFAULT_PACKET_SIZE < 1024*4 - SSL3_RT_DEFAULT_WRITE_OVERHEAD
++#error "SSL3_RT_DEFAULT_PACKET_SIZE is too small."
++#endif
+ n=((p[0]&0x7f)<<8)|p[1];
+- if (n > (1024*4))
++ if (n > SSL3_RT_DEFAULT_PACKET_SIZE - 2)
+ {
+ SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,SSL_R_RECORD_TOO_LARGE);
+ goto err;
+diff -uarp openssl-0.9.8j.orig/ssl/s3_both.c openssl-0.9.8j/ssl/s3_both.c
+--- openssl-0.9.8j.orig/ssl/s3_both.c 2005-04-26 09:02:39.000000000 -0700
++++ openssl-0.9.8j/ssl/s3_both.c 2009-04-21 11:28:58.545691000 -0700
+@@ -594,11 +594,18 @@ int ssl3_setup_buffers(SSL *s)
+
+ if (s->s3->rbuf.buf == NULL)
+ {
+- if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
+- extra=SSL3_RT_MAX_EXTRA;
++ if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)
++ {
++ len = SSL3_RT_DEFAULT_PACKET_SIZE;
++ }
+ else
+- extra=0;
+- len = SSL3_RT_MAX_PACKET_SIZE + extra;
++ {
++ if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
++ extra=SSL3_RT_MAX_EXTRA;
++ else
++ extra=0;
++ len = SSL3_RT_MAX_PACKET_SIZE + extra;
++ }
+ if ((p=OPENSSL_malloc(len)) == NULL)
+ goto err;
+ s->s3->rbuf.buf = p;
+@@ -607,8 +614,15 @@ int ssl3_setup_buffers(SSL *s)
+
+ if (s->s3->wbuf.buf == NULL)
+ {
+- len = SSL3_RT_MAX_PACKET_SIZE;
+- len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */
++ if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)
++ {
++ len = SSL3_RT_DEFAULT_PACKET_SIZE;
++ }
++ else
++ {
++ len = SSL3_RT_MAX_PACKET_SIZE;
++ }
++ len += SSL3_RT_DEFAULT_WRITE_OVERHEAD; /* extra space for empty fragment */
+ if ((p=OPENSSL_malloc(len)) == NULL)
+ goto err;
+ s->s3->wbuf.buf = p;
+diff -uarp openssl-0.9.8j.orig/ssl/s3_pkt.c openssl-0.9.8j/ssl/s3_pkt.c
+--- openssl-0.9.8j.orig/ssl/s3_pkt.c 2008-10-10 03:41:32.000000000 -0700
++++ openssl-0.9.8j/ssl/s3_pkt.c 2009-04-21 11:54:56.386910000 -0700
+@@ -250,7 +250,8 @@ static int ssl3_get_record(SSL *s)
+ extra=SSL3_RT_MAX_EXTRA;
+ else
+ extra=0;
+- if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
++ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) &&
++ extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
+ {
+ /* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ * set after ssl3_setup_buffers() was done */
+@@ -303,6 +304,21 @@ again:
+ goto f_err;
+ }
+
++ /* If we receive a valid record larger than the current buffer size,
++ * allocate some memory for it.
++ */
++ if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
++ {
++ if ((p=OPENSSL_realloc(s->s3->rbuf.buf, rr->length + SSL3_RT_HEADER_LENGTH))==NULL)
++ {
++ SSLerr(SSL_F_SSL3_GET_RECORD,ERR_R_INTERNAL_ERROR);
++ goto err;
++ }
++ s->s3->rbuf.buf=p;
++ s->s3->rbuf.len=rr->length + SSL3_RT_HEADER_LENGTH;
++ s->packet= &(s->s3->rbuf.buf[0]);
++ }
++
+ /* now s->rstate == SSL_ST_READ_BODY */
+ }
+
+@@ -516,6 +532,7 @@ int ssl3_write_bytes(SSL *s, int type, c
+ const unsigned char *buf=buf_;
+ unsigned int tot,n,nw;
+ int i;
++ unsigned int max_plain_length;
+
+ s->rwstate=SSL_NOTHING;
+ tot=s->s3->wnum;
+@@ -535,8 +552,13 @@ int ssl3_write_bytes(SSL *s, int type, c
+ n=(len-tot);
+ for (;;)
+ {
+- if (n > SSL3_RT_MAX_PLAIN_LENGTH)
+- nw=SSL3_RT_MAX_PLAIN_LENGTH;
++ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS))
++ max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH;
++ else
++ max_plain_length = SSL3_RT_DEFAULT_PLAIN_LENGTH;
++
++ if (n > max_plain_length)
++ nw = max_plain_length;
+ else
+ nw=n;
+
+@@ -620,7 +642,9 @@ static int do_ssl3_write(SSL *s, int typ
+ if (prefix_len <= 0)
+ goto err;
+
+- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
++ if (s->s3->wbuf.len < (size_t)prefix_len +
++ ((SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) ? SSL3_RT_DEFAULT_PACKET_SIZE :
++ SSL3_RT_MAX_PACKET_SIZE))
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+diff -uarp openssl-0.9.8j.orig/ssl/ssl.h openssl-0.9.8j/ssl/ssl.h
+--- openssl-0.9.8j.orig/ssl/ssl.h 2009-04-21 11:28:38.824414000 -0700
++++ openssl-0.9.8j/ssl/ssl.h 2009-04-21 11:28:58.560693000 -0700
+@@ -554,7 +554,9 @@ typedef struct ssl_session_st
+ #define SSL_MODE_AUTO_RETRY 0x00000004L
+ /* Don't attempt to automatically build certificate chain */
+ #define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
+-
++/* Use small read and write buffers: (a) lazy allocate read buffers for
++ * large incoming records, and (b) limit the size of outgoing records. */
++#define SSL_MODE_SMALL_BUFFERS 0x00000010L
+
+ /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
+ * they cannot be used to clear bits. */
+diff -uarp openssl-0.9.8j.orig/ssl/ssl3.h openssl-0.9.8j/ssl/ssl3.h
+--- openssl-0.9.8j.orig/ssl/ssl3.h 2009-04-21 11:28:38.842397000 -0700
++++ openssl-0.9.8j/ssl/ssl3.h 2009-04-21 11:28:58.565695000 -0700
+@@ -253,6 +253,9 @@ extern "C" {
+ #define SSL3_RT_MAX_EXTRA (16384)
+ #endif
+
++/* Default buffer length used for writen records. Thus a generated record
++ * will contain plaintext no larger than this value. */
++#define SSL3_RT_DEFAULT_PLAIN_LENGTH 2048
+ #define SSL3_RT_MAX_PLAIN_LENGTH 16384
+ #ifdef OPENSSL_NO_COMP
+ #define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
+@@ -260,6 +263,12 @@ extern "C" {
+ #define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH)
+ #endif
+ #define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
++/* Extra space for empty fragment, headers, MAC, and padding. */
++#define SSL3_RT_DEFAULT_WRITE_OVERHEAD 256
++#define SSL3_RT_DEFAULT_PACKET_SIZE 4096 - SSL3_RT_DEFAULT_WRITE_OVERHEAD
++#if SSL3_RT_DEFAULT_PLAIN_LENGTH + SSL3_RT_DEFAULT_WRITE_OVERHEAD > SSL3_RT_DEFAULT_PACKET_SIZE
++#error "Insufficient space allocated for write buffers."
++#endif
+ #define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
+ #define SSL3_RT_MAX_DATA_SIZE (1024*1024)
+
+diff -uarp openssl-0.9.8j.orig/ssl/ssltest.c openssl-0.9.8j/ssl/ssltest.c
+--- openssl-0.9.8j.orig/ssl/ssltest.c 2009-01-07 02:48:23.000000000 -0800
++++ openssl-0.9.8j/ssl/ssltest.c 2009-04-21 11:28:58.572707000 -0700
+@@ -277,6 +277,8 @@ static void sv_usage(void)
+ " (default is sect163r2).\n");
+ #endif
+ fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
++ fprintf(stderr," -c_small_records - enable client side use of small SSL record buffers\n");
++ fprintf(stderr," -s_small_records - enable server side use of small SSL record buffers\n");
+ }
+
+ static void print_details(SSL *c_ssl, const char *prefix)
+@@ -431,6 +433,9 @@ int main(int argc, char *argv[])
+ #ifdef OPENSSL_FIPS
+ int fips_mode=0;
+ #endif
++ int ssl_mode = 0;
++ int c_small_records=0;
++ int s_small_records=0;
+
+ verbose = 0;
+ debug = 0;
+@@ -619,6 +624,14 @@ int main(int argc, char *argv[])
+ {
+ test_cipherlist = 1;
+ }
++ else if (strcmp(*argv, "-c_small_records") == 0)
++ {
++ c_small_records = 1;
++ }
++ else if (strcmp(*argv, "-s_small_records") == 0)
++ {
++ s_small_records = 1;
++ }
+ else
+ {
+ fprintf(stderr,"unknown option %s\n",*argv);
+@@ -755,6 +768,21 @@ bad:
+ SSL_CTX_set_cipher_list(s_ctx,cipher);
+ }
+
++ ssl_mode = 0;
++ if (c_small_records)
++ {
++ ssl_mode = SSL_CTX_get_mode(c_ctx);
++ ssl_mode |= SSL_MODE_SMALL_BUFFERS;
++ SSL_CTX_set_mode(c_ctx, ssl_mode);
++ }
++ ssl_mode = 0;
++ if (s_small_records)
++ {
++ ssl_mode = SSL_CTX_get_mode(s_ctx);
++ ssl_mode |= SSL_MODE_SMALL_BUFFERS;
++ SSL_CTX_set_mode(s_ctx, ssl_mode);
++ }
++
+ #ifndef OPENSSL_NO_DH
+ if (!no_dhe)
+ {
+diff -uarp openssl-0.9.8j.orig/test/testssl openssl-0.9.8j/test/testssl
+--- openssl-0.9.8j.orig/test/testssl 2005-02-01 15:48:36.000000000 -0800
++++ openssl-0.9.8j/test/testssl 2009-04-21 11:28:58.594684000 -0700
+@@ -70,6 +70,16 @@ $ssltest -client_auth $CA $extra || exit
+ echo test sslv2/sslv3 with both client and server authentication
+ $ssltest -server_auth -client_auth $CA $extra || exit 1
+
++echo test sslv2/sslv3 with both client and server authentication and small client buffers
++$ssltest -server_auth -client_auth -c_small_records $CA $extra || exit 1
++
++echo test sslv2/sslv3 with both client and server authentication and small server buffers
++$ssltest -server_auth -client_auth -s_small_records $CA $extra || exit 1
++
++echo test sslv2/sslv3 with both client and server authentication and small client and server buffers
++$ssltest -server_auth -client_auth -c_small_records -s_small_records $CA $extra || exit 1
++
++
+ echo test sslv2 via BIO pair
+ $ssltest -bio_pair -ssl2 $extra || exit 1
+
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index eb56cf9..7d464b4 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -561,6 +561,21 @@
goto f_err;
}
+ /* If we receive a valid record larger than the current buffer size,
+ * allocate some memory for it.
+ */
+ if (rr->length > s->s3->rbuf.len - DTLS1_RT_HEADER_LENGTH)
+ {
+ if ((p=OPENSSL_realloc(s->s3->rbuf.buf, rr->length + DTLS1_RT_HEADER_LENGTH))==NULL)
+ {
+ SSLerr(SSL_F_DTLS1_GET_RECORD,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ s->s3->rbuf.buf=p;
+ s->s3->rbuf.len=rr->length + DTLS1_RT_HEADER_LENGTH;
+ s->packet= &(s->s3->rbuf.buf[0]);
+ }
+
s->client_version = version;
/* now s->rstate == SSL_ST_READ_BODY */
}
@@ -1226,6 +1241,7 @@
unsigned int tot,n,nw;
int i;
unsigned int mtu;
+ unsigned int max_mtu;
s->rwstate=SSL_NOTHING;
tot=s->s3->wnum;
@@ -1240,8 +1256,17 @@
#endif
mtu = s->d1->mtu;
- if (mtu > SSL3_RT_MAX_PLAIN_LENGTH)
- mtu = SSL3_RT_MAX_PLAIN_LENGTH;
+ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS))
+ {
+ max_mtu = SSL3_RT_MAX_PLAIN_LENGTH;
+ }
+ else
+ {
+ max_mtu = SSL3_RT_DEFAULT_PLAIN_LENGTH;
+ }
+
+ if (mtu > max_mtu)
+ mtu = max_mtu;
if (n > mtu)
nw=mtu;
@@ -1327,7 +1352,9 @@
if (prefix_len <= 0)
goto err;
- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ if (s->s3->wbuf.len < (size_t)prefix_len +
+ ((SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) ? SSL3_RT_DEFAULT_PACKET_SIZE :
+ SSL3_RT_MAX_PACKET_SIZE))
{
/* insufficient space */
SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR);
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index ba06e7a..468251a 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -405,8 +405,13 @@
v[0] = p[3]; /* == SSL3_VERSION_MAJOR */
v[1] = p[4];
+/* The SSL2 protocol allows n to be larger, just pick
+ * a reasonable buffer size. */
+#if SSL3_RT_DEFAULT_PACKET_SIZE < 1024*4 - SSL3_RT_DEFAULT_WRITE_OVERHEAD
+#error "SSL3_RT_DEFAULT_PACKET_SIZE is too small."
+#endif
n=((p[0]&0x7f)<<8)|p[1];
- if (n > (1024*4))
+ if (n > SSL3_RT_DEFAULT_PACKET_SIZE - 2)
{
SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,SSL_R_RECORD_TOO_LARGE);
goto err;
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 2ecfbb7..d5bb99c 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -594,11 +594,18 @@
if (s->s3->rbuf.buf == NULL)
{
- if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
- extra=SSL3_RT_MAX_EXTRA;
+ if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)
+ {
+ len = SSL3_RT_DEFAULT_PACKET_SIZE;
+ }
else
- extra=0;
- len = SSL3_RT_MAX_PACKET_SIZE + extra;
+ {
+ if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
+ extra=SSL3_RT_MAX_EXTRA;
+ else
+ extra=0;
+ len = SSL3_RT_MAX_PACKET_SIZE + extra;
+ }
if ((p=OPENSSL_malloc(len)) == NULL)
goto err;
s->s3->rbuf.buf = p;
@@ -607,8 +614,15 @@
if (s->s3->wbuf.buf == NULL)
{
- len = SSL3_RT_MAX_PACKET_SIZE;
- len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */
+ if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)
+ {
+ len = SSL3_RT_DEFAULT_PACKET_SIZE;
+ }
+ else
+ {
+ len = SSL3_RT_MAX_PACKET_SIZE;
+ }
+ len += SSL3_RT_DEFAULT_WRITE_OVERHEAD; /* extra space for empty fragment */
if ((p=OPENSSL_malloc(len)) == NULL)
goto err;
s->s3->wbuf.buf = p;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 5030848..47dd34f 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -454,14 +454,20 @@
}
else
{
-#ifndef OPENSSL_NO_TLSEXT
- /* Allow NewSessionTicket if ticket expected */
- if (s->tlsext_ticket_expected)
- s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+ if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && SSL_get_cipher_bits(s, NULL) >= 128)
+ {
+ s->s3->tmp.next_state=SSL3_ST_CUTTHROUGH_COMPLETE;
+ }
else
+ {
+#ifndef OPENSSL_NO_TLSEXT
+ /* Allow NewSessionTicket if ticket expected */
+ if (s->tlsext_ticket_expected)
+ s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
#endif
-
- s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+ s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+ }
}
s->init_num=0;
break;
@@ -512,6 +518,22 @@
s->state=s->s3->tmp.next_state;
break;
+ case SSL3_ST_CUTTHROUGH_COMPLETE:
+#ifndef OPENSSL_NO_TLSEXT
+ /* Allow NewSessionTicket if ticket expected */
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+#endif
+ s->state=SSL3_ST_CR_FINISHED_A;
+
+ /* Allow application writes to go through. Note that SSL3_FLAGS_DELAY_CLIENT_FINISHED
+ * is not supported on cutthrough connections (just for simplicity) */
+ ssl_free_wbio_buffer(s);
+ ret = 1;
+ goto end;
+ /* break; */
+
case SSL_ST_OK:
/* clean a few things up */
ssl3_cleanup_key_block(s);
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 9476dcd..e32174d 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -250,7 +250,8 @@
extra=SSL3_RT_MAX_EXTRA;
else
extra=0;
- if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
+ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) &&
+ extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
{
/* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
* set after ssl3_setup_buffers() was done */
@@ -303,6 +304,21 @@
goto f_err;
}
+ /* If we receive a valid record larger than the current buffer size,
+ * allocate some memory for it.
+ */
+ if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
+ {
+ if ((p=OPENSSL_realloc(s->s3->rbuf.buf, rr->length + SSL3_RT_HEADER_LENGTH))==NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_RECORD,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ s->s3->rbuf.buf=p;
+ s->s3->rbuf.len=rr->length + SSL3_RT_HEADER_LENGTH;
+ s->packet= &(s->s3->rbuf.buf[0]);
+ }
+
/* now s->rstate == SSL_ST_READ_BODY */
}
@@ -516,6 +532,7 @@
const unsigned char *buf=buf_;
unsigned int tot,n,nw;
int i;
+ unsigned int max_plain_length;
s->rwstate=SSL_NOTHING;
tot=s->s3->wnum;
@@ -535,8 +552,13 @@
n=(len-tot);
for (;;)
{
- if (n > SSL3_RT_MAX_PLAIN_LENGTH)
- nw=SSL3_RT_MAX_PLAIN_LENGTH;
+ if (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS))
+ max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH;
+ else
+ max_plain_length = SSL3_RT_DEFAULT_PLAIN_LENGTH;
+
+ if (n > max_plain_length)
+ nw = max_plain_length;
else
nw=n;
@@ -620,7 +642,9 @@
if (prefix_len <= 0)
goto err;
- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ if (s->s3->wbuf.len < (size_t)prefix_len +
+ ((SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) ? SSL3_RT_DEFAULT_PACKET_SIZE :
+ SSL3_RT_MAX_PACKET_SIZE))
{
/* insufficient space */
SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index ff8a128..0e0bc6e 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -554,7 +554,13 @@
#define SSL_MODE_AUTO_RETRY 0x00000004L
/* Don't attempt to automatically build certificate chain */
#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
-
+/* Use small read and write buffers: (a) lazy allocate read buffers for
+ * large incoming records, and (b) limit the size of outgoing records. */
+#define SSL_MODE_SMALL_BUFFERS 0x00000010L
+/* When set, clients may send application data before receipt of CCS
+ * and Finished. This mode enables full-handshakes to 'complete' in
+ * one RTT. */
+#define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000020L
/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
* they cannot be used to clear bits. */
@@ -1095,10 +1101,12 @@
/* Is the SSL_connection established? */
#define SSL_get_state(a) SSL_state(a)
#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK)
-#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT)
+#define SSL_in_init(a) ((SSL_state(a)&SSL_ST_INIT) && \
+ !SSL_cutthrough_complete(a))
#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE)
#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT)
#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT)
+int SSL_cutthrough_complete(const SSL *s);
/* The following 2 states are kept in ssl->rstate when reads fail,
* you should not need these */
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 4b1e2e9..803e13a 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -253,6 +253,9 @@
#define SSL3_RT_MAX_EXTRA (16384)
#endif
+/* Default buffer length used for writen records. Thus a generated record
+ * will contain plaintext no larger than this value. */
+#define SSL3_RT_DEFAULT_PLAIN_LENGTH 2048
#define SSL3_RT_MAX_PLAIN_LENGTH 16384
#ifdef OPENSSL_NO_COMP
#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH
@@ -260,6 +263,12 @@
#define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH)
#endif
#define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
+/* Extra space for empty fragment, headers, MAC, and padding. */
+#define SSL3_RT_DEFAULT_WRITE_OVERHEAD 256
+#define SSL3_RT_DEFAULT_PACKET_SIZE 4096 - SSL3_RT_DEFAULT_WRITE_OVERHEAD
+#if SSL3_RT_DEFAULT_PLAIN_LENGTH + SSL3_RT_DEFAULT_WRITE_OVERHEAD > SSL3_RT_DEFAULT_PACKET_SIZE
+#error "Insufficient space allocated for write buffers."
+#endif
#define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
#define SSL3_RT_MAX_DATA_SIZE (1024*1024)
@@ -447,6 +456,7 @@
/*client */
/* extra state */
#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
+#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT)
/* write to server */
#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 893abff..4c56e7a 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2696,7 +2696,17 @@
SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
}
-
+int SSL_cutthrough_complete(const SSL *s)
+ {
+ return (!s->server && /* cutthrough only applies to clients */
+ !s->hit && /* full-handshake */
+ s->version >= SSL3_VERSION &&
+ s->s3->in_read_app_data == 0 && /* cutthrough only applies to write() */
+ (SSL_get_mode((SSL*)s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && /* cutthrough enabled */
+ SSL_get_cipher_bits(s, NULL) >= 128 && /* strong cipher choosen */
+ (s->state == SSL3_ST_CR_SESSION_TICKET_A || /* ready to write app-data*/
+ s->state == SSL3_ST_CR_FINISHED_A));
+ }
#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
#include "../crypto/bio/bss_file.c"
diff --git a/ssl/ssltest.c b/ssl/ssltest.c
index b09c542..09d3502 100644
--- a/ssl/ssltest.c
+++ b/ssl/ssltest.c
@@ -277,6 +277,8 @@
" (default is sect163r2).\n");
#endif
fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+ fprintf(stderr," -c_small_records - enable client side use of small SSL record buffers\n");
+ fprintf(stderr," -s_small_records - enable server side use of small SSL record buffers\n");
}
static void print_details(SSL *c_ssl, const char *prefix)
@@ -431,6 +433,9 @@
#ifdef OPENSSL_FIPS
int fips_mode=0;
#endif
+ int ssl_mode = 0;
+ int c_small_records=0;
+ int s_small_records=0;
verbose = 0;
debug = 0;
@@ -619,6 +624,14 @@
{
test_cipherlist = 1;
}
+ else if (strcmp(*argv, "-c_small_records") == 0)
+ {
+ c_small_records = 1;
+ }
+ else if (strcmp(*argv, "-s_small_records") == 0)
+ {
+ s_small_records = 1;
+ }
else
{
fprintf(stderr,"unknown option %s\n",*argv);
@@ -755,6 +768,21 @@
SSL_CTX_set_cipher_list(s_ctx,cipher);
}
+ ssl_mode = 0;
+ if (c_small_records)
+ {
+ ssl_mode = SSL_CTX_get_mode(c_ctx);
+ ssl_mode |= SSL_MODE_SMALL_BUFFERS;
+ SSL_CTX_set_mode(c_ctx, ssl_mode);
+ }
+ ssl_mode = 0;
+ if (s_small_records)
+ {
+ ssl_mode = SSL_CTX_get_mode(s_ctx);
+ ssl_mode |= SSL_MODE_SMALL_BUFFERS;
+ SSL_CTX_set_mode(s_ctx, ssl_mode);
+ }
+
#ifndef OPENSSL_NO_DH
if (!no_dhe)
{