summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2017-03-24 17:58:58 +1030
committerPeter Dettman <peter.dettman@bouncycastle.org>2017-03-24 17:58:58 +1030
commit29d257cfe975d62169584ad1b8896157d415c5d7 (patch)
tree472b1b39cb48675ebbe6bda3db8c54c7550e3a1d /crypto
parentReduce TLS memory usage (diff)
downloadBouncyCastle.NET-ed25519-29d257cfe975d62169584ad1b8896157d415c5d7.tar.xz
Avoid copies when handshake records not fragmented
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/crypto/tls/ByteQueue.cs15
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs128
2 files changed, 81 insertions, 62 deletions
diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs
index f9d4ee606..b4df6850e 100644
--- a/crypto/src/crypto/tls/ByteQueue.cs
+++ b/crypto/src/crypto/tls/ByteQueue.cs
@@ -48,6 +48,8 @@ namespace Org.BouncyCastle.Crypto.Tls
          */
         private int available = 0;
 
+        private bool readOnlyBuf = false;
+
         public ByteQueue()
             : this(DefaultCapacity)
         {
@@ -55,7 +57,15 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public ByteQueue(int capacity)
         {
-            this.databuf = new byte[capacity];
+            this.databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity];
+        }
+
+        public ByteQueue(byte[] buf, int off, int len)
+        {
+            this.databuf = buf;
+            this.skipped = off;
+            this.available = len;
+            this.readOnlyBuf = true;
         }
 
         /// <summary>Add some data to our buffer.</summary>
@@ -67,6 +77,9 @@ namespace Org.BouncyCastle.Crypto.Tls
             int offset,
             int len)
         {
+            if (readOnlyBuf)
+                throw new InvalidOperationException("Cannot add data to read-only buffer");
+
             if ((skipped + available + len) > databuf.Length)
             {
                 int desiredSize = ByteQueue.NextTwoPow(available + len);
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 69361bf6f..490580fad 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.Tls
          */
         private ByteQueue mApplicationDataQueue = new ByteQueue(0);
         private ByteQueue mAlertQueue = new ByteQueue(2);
-        private ByteQueue mHandshakeQueue = new ByteQueue();
+        private ByteQueue mHandshakeQueue = new ByteQueue(0);
     //    private ByteQueue mHeartbeatQueue = new ByteQueue();
 
         /*
@@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len)
+        protected internal void ProcessRecord(byte protocol, byte[] buf, int off, int len)
         {
             /*
              * Have a look at the protocol type, and add it to the correct queue.
@@ -242,8 +242,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
             case ContentType.alert:
             {
-                mAlertQueue.AddData(buf, offset, len);
-                ProcessAlert();
+                mAlertQueue.AddData(buf, off, len);
+                ProcessAlertQueue();
                 break;
             }
             case ContentType.application_data:
@@ -251,19 +251,32 @@ namespace Org.BouncyCastle.Crypto.Tls
                 if (!mAppDataReady)
                     throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
-                mApplicationDataQueue.AddData(buf, offset, len);
-                ProcessApplicationData();
+                mApplicationDataQueue.AddData(buf, off, len);
+                ProcessApplicationDataQueue();
                 break;
             }
             case ContentType.change_cipher_spec:
             {
-                ProcessChangeCipherSpec(buf, offset, len);
+                ProcessChangeCipherSpec(buf, off, len);
                 break;
             }
             case ContentType.handshake:
             {
-                mHandshakeQueue.AddData(buf, offset, len);
-                ProcessHandshake();
+                if (mHandshakeQueue.Available > 0)
+                {
+                    mHandshakeQueue.AddData(buf, off, len);
+                    ProcessHandshakeQueue(mHandshakeQueue);
+                }
+                else
+                {
+                    ByteQueue tmpQueue = new ByteQueue(buf, off, len);
+                    ProcessHandshakeQueue(tmpQueue);
+                    int remaining = tmpQueue.Available;
+                    if (remaining > 0)
+                    {
+                        mHandshakeQueue.AddData(buf, off + len - remaining, remaining);
+                    }
+                }
                 break;
             }
             //case ContentType.heartbeat:
@@ -282,71 +295,64 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        private void ProcessHandshake()
+        private void ProcessHandshakeQueue(ByteQueue queue)
         {
-            bool read;
-            do
+            while (queue.Available >= 4)
             {
-                read = false;
                 /*
                  * We need the first 4 bytes, they contain type and length of the message.
                  */
-                if (mHandshakeQueue.Available >= 4)
-                {
-                    byte[] beginning = new byte[4];
-                    mHandshakeQueue.Read(beginning, 0, 4, 0);
-                    byte type = TlsUtilities.ReadUint8(beginning, 0);
-                    int length = TlsUtilities.ReadUint24(beginning, 1);
-                    int totalLength = 4 + length;
+                byte[] beginning = new byte[4];
+                queue.Read(beginning, 0, 4, 0);
+                byte type = TlsUtilities.ReadUint8(beginning, 0);
+                int length = TlsUtilities.ReadUint24(beginning, 1);
+                int totalLength = 4 + length;
 
-                    /*
-                     * Check if we have enough bytes in the buffer to read the full message.
-                     */
-                    if (mHandshakeQueue.Available >= totalLength)
+                /*
+                 * Check if we have enough bytes in the buffer to read the full message.
+                 */
+                if (queue.Available < totalLength)
+                    break;
+
+                CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
+
+                /*
+                 * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
+                 * starting at client hello up to, but not including, this finished message.
+                 * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
+                 */
+                switch (type)
+                {
+                case HandshakeType.hello_request:
+                    break;
+                case HandshakeType.finished:
+                default:
+                {
+                    TlsContext ctx = Context;
+                    if (type == HandshakeType.finished
+                        && this.mExpectedVerifyData == null
+                        && ctx.SecurityParameters.MasterSecret != null)
                     {
-                        CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
+                        this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
+                    }
 
-                        /*
-                         * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
-                         * starting at client hello up to, but not including, this finished message.
-                         * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
-                         */
-                        switch (type)
-                        {
-                        case HandshakeType.hello_request:
-                            break;
-                        case HandshakeType.finished:
-                        default:
-                        {
-                            TlsContext ctx = Context;
-                            if (type == HandshakeType.finished
-                                && this.mExpectedVerifyData == null
-                                && ctx.SecurityParameters.MasterSecret != null)
-                            {
-                                this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
-                            }
-
-                            mHandshakeQueue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength);
-                            break;
-                        }
-                        }
+                    queue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength);
+                    break;
+                }
+                }
 
-                        mHandshakeQueue.RemoveData(4);
+                queue.RemoveData(4);
 
-                        MemoryStream buf = mHandshakeQueue.ReadFrom(length);
+                MemoryStream buf = queue.ReadFrom(length);
 
-                        /*
-                         * Now, parse the message.
-                         */
-                        HandleHandshakeMessage(type, buf);
-                        read = true;
-                    }
-                }
+                /*
+                 * Now, parse the message.
+                 */
+                HandleHandshakeMessage(type, buf);
             }
-            while (read);
         }
 
-        private void ProcessApplicationData()
+        private void ProcessApplicationDataQueue()
         {
             /*
              * There is nothing we need to do here.
@@ -355,7 +361,7 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
         }
 
-        private void ProcessAlert()
+        private void ProcessAlertQueue()
         {
             while (mAlertQueue.Available >= 2)
             {