Пример #1
0
 private BufferOffsetSize[] ConcatenateBuffersOnWin9x(BufferOffsetSize[] buffers)
 {
     if (ComNetOS.IsWin9x && (buffers.Length > 0x10))
     {
         int num;
         BufferOffsetSize[] sizeArray = new BufferOffsetSize[0x10];
         for (num = 0; num < 0x10; num++)
         {
             sizeArray[num] = buffers[num];
         }
         int size = 0;
         for (num = 15; num < buffers.Length; num++)
         {
             size += buffers[num].Size;
         }
         if (size > 0)
         {
             sizeArray[15] = new BufferOffsetSize(new byte[size], 0, size, false);
             size          = 0;
             for (num = 15; num < buffers.Length; num++)
             {
                 Buffer.BlockCopy(buffers[num].Buffer, buffers[num].Offset, sizeArray[15].Buffer, size, buffers[num].Size);
                 size += buffers[num].Size;
             }
         }
         buffers = sizeArray;
     }
     return(buffers);
 }
Пример #2
0
		internal void MultipleSend (BufferOffsetSize[] buffers, SocketFlags socketFlags)
		{
			var segments = new ArraySegment<byte> [buffers.Length];
			for (int i = 0; i < buffers.Length; i++)
				segments [i] = new ArraySegment<byte> (buffers [i].Buffer, buffers [i].Offset, buffers [i].Size);
			Send (segments, socketFlags);
		}
Пример #3
0
 /// <devdoc>
 ///    <para>
 ///       Due to Winsock restrictions
 ///       If on Win9x platforms and the number of buffers are more than 16, performs
 ///         concatenation of the buffers, so that we have 16 buffers.
 ///    </para>
 /// </devdoc>
 private BufferOffsetSize[] ConcatenateBuffersOnWin9x(BufferOffsetSize[] buffers)
 {
     if (ComNetOS.IsWin9x && buffers.Length > 16)
     {
         // We met the limitation of winsock on Win9x
         // Combine buffers after the 15th into one so overall number does not exceed 16
         BufferOffsetSize[] newBuffers = new BufferOffsetSize[16];
         int i;
         for (i = 0; i < 16; ++i)
         {
             newBuffers[i] = buffers[i];
         }
         int size = 0;
         for (i = 15; i < buffers.Length; ++i)
         {
             size += buffers[i].Size;
         }
         if (size > 0)
         {
             newBuffers[15] = new BufferOffsetSize(new byte[size], 0, size, false);
             for (size = 0, i = 15; i < buffers.Length; size += buffers[i].Size, ++i)
             {
                 System.Buffer.BlockCopy(buffers[i].Buffer, buffers[i].Offset, newBuffers[15].Buffer, size, buffers[i].Size);
             }
         }
         buffers = newBuffers;
     }
     return(buffers);
 }
Пример #4
0
		internal IAsyncResult BeginMultipleSend (BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
		{
			var segments = new ArraySegment<byte> [buffers.Length];
			for (int i = 0; i < buffers.Length; i++)
				segments [i] = new ArraySegment<byte> (buffers [i].Buffer, buffers [i].Offset, buffers [i].Size);
			return BeginSend (segments, socketFlags, callback, state);
		}
Пример #5
0
        public IBufferOffsetSize Decrypt(ContentType contentType, IBufferOffsetSize input)
        {
            var output = new BufferOffsetSize(input.Size);
            var ret    = Decrypt(contentType, input, output);

            output.TruncateTo(ret);
            return(output);
        }
 //
 // Constructor:
 //
 internal NestedMultipleAsyncResult(Object asyncObject, Object asyncState, AsyncCallback asyncCallback, BufferOffsetSize[] buffers)
 : base( asyncObject, asyncState, asyncCallback ) {
     Buffers = buffers;
     Size = 0;
     for (int i = 0; i < Buffers.Length; i++) {
         Size += Buffers[i].Size;
     }
 }
Пример #7
0
        public IBufferOffsetSize Encrypt(ContentType contentType, IBufferOffsetSize data)
        {
            var output = new BufferOffsetSize(GetEncryptedSize(data.Size));
            var ret    = Encrypt(contentType, data, output);

            output.TruncateTo(ret);
            return(output);
        }
Пример #8
0
        public MobileAuthenticatedStream(Stream innerStream, bool leaveInnerStreamOpen, MonoTlsSettings settings, AppleTlsProvider provider)
            : base(innerStream, leaveInnerStreamOpen)
        {
            Settings = settings;
            Provider = provider;

            readBuffer = new BufferOffsetSize (new byte [16384], 0, 0);
            writeBuffer = new BufferOffsetSize (new byte [16384], 0, 0);
        }
Пример #9
0
        //
        // Combined sync/async write method. For sync case asyncRequest==null
        //
        private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            if (_SslState.LastPayload != null)
            {
                //
                // !!! LastPayload Only used in TlsStream  for HTTP and it needs re-work for a general case !!!
                //
                BufferOffsetSize[] buffers = new BufferOffsetSize[1];
                buffers[0] = new BufferOffsetSize(buffer, offset, count, false);
                if (asyncRequest != null)
                {
                    ProcessWrite(buffers, new SplitWriteAsyncProtocolRequest(asyncRequest.UserAsyncResult));
                }
                else
                {
                    ProcessWrite(buffers, null);
                }
                return;
            }

            ValidateParameters(buffer, offset, count);
            _SslState.CheckThrow(authSuccessCheck: true, shutdownCheck: true);

            if (Interlocked.Exchange(ref _NestedWrite, 1) == 1)
            {
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginWrite":"Write"), "write"));
            }

            bool failed = false;

            try
            {
                StartWriting(buffer, offset, count, asyncRequest);
            }
            catch (Exception e)
            {
                _SslState.FinishWrite();

                failed = true;
                if (e is IOException)
                {
                    throw;
                }
                throw new IOException(SR.GetString(SR.net_io_write), e);
            }
            finally
            {
                if (asyncRequest == null || failed)
                {
                    _NestedWrite = 0;
                }
            }
        }
Пример #10
0
        public        ArraySegment <byte> this[int i]
        {
            get
            {
                var bufferOffsetSizes = _buffers as BufferOffsetSize[];
                if (bufferOffsetSizes != null)
                {
                    BufferOffsetSize element = bufferOffsetSizes[i];
                    return(new ArraySegment <byte>(element.Buffer, element.Offset, element.Size));
                }

                return(((IList <ArraySegment <byte> >)_buffers)[i]);
            }
        }
Пример #11
0
 private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
 {
     if (this._SslState.LastPayload != null)
     {
         BufferOffsetSize[] buffers = new BufferOffsetSize[] { new BufferOffsetSize(buffer, offset, count, false) };
         if (asyncRequest != null)
         {
             this.ProcessWrite(buffers, new SplitWriteAsyncProtocolRequest(asyncRequest.UserAsyncResult));
         }
         else
         {
             this.ProcessWrite(buffers, null);
         }
     }
     else
     {
         this.ValidateParameters(buffer, offset, count);
         if (Interlocked.Exchange(ref this._NestedWrite, 1) == 1)
         {
             throw new NotSupportedException(SR.GetString("net_io_invalidnestedcall", new object[] { (asyncRequest != null) ? "BeginWrite" : "Write", "write" }));
         }
         bool flag = false;
         try
         {
             this.StartWriting(buffer, offset, count, asyncRequest);
         }
         catch (Exception exception)
         {
             this._SslState.FinishWrite();
             flag = true;
             if (exception is IOException)
             {
                 throw;
             }
             throw new IOException(SR.GetString("net_io_write"), exception);
         }
         finally
         {
             if ((asyncRequest == null) || flag)
             {
                 this._NestedWrite = 0;
             }
         }
     }
 }
Пример #12
0
            private static IAsyncResult BeginMultipleWrite(IList <ArraySegment <byte> > sendBuffers, AsyncCallback callback, object asyncState)
            {
                Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL.");
                Contract.Assert(asyncState != null, "'asyncState' MUST NOT be NULL.");
                WebSocketConnection connection = asyncState as WebSocketConnection;

                Contract.Assert(connection != null, "'connection' MUST NOT be NULL.");

                BufferOffsetSize[] buffers = new BufferOffsetSize[sendBuffers.Count];

                for (int index = 0; index < sendBuffers.Count; index++)
                {
                    ArraySegment <byte> sendBuffer = sendBuffers[index];
                    buffers[index] = new BufferOffsetSize(sendBuffer.Array, sendBuffer.Offset, sendBuffer.Count, false);
                }

                WebSocketHelpers.ThrowIfConnectionAborted(connection.m_InnerStream, false);
                return(connection.m_InnerStream.NetworkStream.BeginMultipleWrite(buffers, callback, asyncState));
            }
Пример #13
0
        protected override int Encrypt(DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output)
        {
            // Calculate message MAC
            byte[] mac = null;
            if (IsServer)
            {
                mac = ComputeServerRecordMAC(contentType, input);
            }
            else
            {
                mac = ComputeClientRecordMAC(contentType, input);
            }

                        #if DEBUG_FULL
            if (Cipher.EnableDebugging)
            {
                DebugHelper.WriteLine("RECORD MAC", mac);
            }
                        #endif

            int  plen;
            byte padLen;
            int  totalLength = GetEncryptedSize(input.Size, out plen, out padLen);

            var totalOutput  = new BufferOffsetSize(output.Buffer, output.Offset, totalLength);
            var outputWriter = new TlsBuffer(totalOutput);

            outputWriter.Position += HeaderSize;

            outputWriter.Write(input.Buffer, input.Offset, input.Size);
            outputWriter.Write(mac);

            for (int i = 0; i <= padLen; i++)
            {
                outputWriter.Write(padLen);
            }

            // Encrypt the message
            EncryptRecord(d, totalOutput);
            return(totalLength);
        }
Пример #14
0
        protected async Task ExpectBlob(TestContext ctx, ICommonConnection connection, HandshakeInstrumentType type, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            LogDebug(ctx, 2, "ExpectBlob", connection, type);

            var buffer = new byte [4096];
            var blob   = Instrumentation.GetTextBuffer(type);
            var ret    = await connection.Stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);

            LogDebug(ctx, 2, "ExpectBlob #1", connection, type, ret);

            if (ctx.Expect(ret, Is.GreaterThan(0), "read success"))
            {
                var result = new BufferOffsetSize(buffer, 0, ret);

                ctx.Expect(result, new IsEqualBlob(blob), "blob");
            }

            LogDebug(ctx, 2, "ExpectBlob done", connection, type);
        }
Пример #15
0
        public void TestDecryptWithInvalidPadding2(TestContext ctx, [TestHost] IEncryptionTestHost host)
        {
            var input = GetBuffer(Data11Result);

            var modified = new TlsBuffer(input.Size);

            modified.Write(input.Buffer);

            // Flip a bit in the last byte, this will affect the padding size.
            modified.Buffer [modified.Size - 1] ^= 0x01;

            input = new BufferOffsetSize(modified.Buffer, 0, modified.Size);

            try {
                host.Decrypt(input);
                ctx.AssertFail("#1");
            } catch (Exception ex) {
                ctx.Assert(ex, Is.InstanceOf <TlsException> (), "#2");
                var tlsEx = (TlsException)ex;
                ctx.Assert(tlsEx.Alert.Level, Is.EqualTo(AlertLevel.Fatal), "#3");
                ctx.Assert(tlsEx.Alert.Description, Is.EqualTo(AlertDescription.BadRecordMAC), "#4");
            }
        }
Пример #16
0
        public void TestDecryptWithInvalidPadding(TestContext ctx, [TestHost] IEncryptionTestHost host)
        {
            var input = GetBuffer(ExtraPaddingResult);

            var modified = new TlsBuffer(input.Size);

            modified.Write(input.Buffer);

            var theOffset = modified.Size - (2 * host.BlockSize) - 5;

            modified.Buffer [theOffset] ^= 0x01;

            input = new BufferOffsetSize(modified.Buffer, 0, modified.Size);

            try {
                host.Decrypt(input);
                ctx.AssertFail("#1");
            } catch (Exception ex) {
                ctx.Assert(ex, Is.InstanceOf <TlsException> (), "#2");
                var tlsEx = (TlsException)ex;
                ctx.Assert(tlsEx.Alert.Level, Is.EqualTo(AlertLevel.Fatal), "#3");
                ctx.Assert(tlsEx.Alert.Description, Is.EqualTo(AlertDescription.BadRecordMAC), "#4");
            }
        }
Пример #17
0
        internal virtual IAsyncResult BeginMultipleWrite(
            BufferOffsetSize[] buffers,
            AsyncCallback callback,
            Object state) {
            //
            // parameter validation
            //
            if (buffers == null) {
                throw new ArgumentNullException("buffers");
            }

            Socket chkStreamSocket = m_StreamSocket;
            if(chkStreamSocket == null) {
                throw new IOException(SR.GetString(SR.net_io_writefailure));
            }

            try {
                //
                // call BeginMultipleSend on the Socket.
                //
                IAsyncResult asyncResult =
                    chkStreamSocket.BeginMultipleSend(
                        buffers,
                        SocketFlags.None,
                        callback,
                        state);

                return asyncResult;
            }
            catch (Exception exception) {
                //
                // some sort of error occured on the socket call,
                // set the SocketException as InnerException and throw
                //
                throw new IOException(SR.GetString(SR.net_io_writefailure), exception);
            }
        }
Пример #18
0
		IAsyncResult BeginReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, AsyncCallback asyncCallback, object asyncState)
		{
			LazyAsyncResult lazyResult = new LazyAsyncResult (this, asyncState, asyncCallback);
			ProcessReadOrWrite (ref nestedRequest, ref internalBuffer, operation, userBuffer, lazyResult);
			return lazyResult;
		}
		async Task RunMainLoopBlob (TestContext ctx, HandshakeInstrumentType type, CancellationToken cancellationToken)
		{
			var expected = Instrumentation.GetTextBuffer (type).GetBuffer ();

			var buffer = new byte [4096];
			int ret = await Server.Stream.ReadAsync (buffer, 0, buffer.Length);
			ctx.Assert (ret, Is.EqualTo (expected.Length));

			buffer = new BufferOffsetSize (buffer, 0, ret).GetBuffer ();

			ctx.Assert (buffer, Is.EqualTo (expected), "blob");

			await Shutdown (ctx, SupportsCleanShutdown, true, cancellationToken);
		}
Пример #20
0
		byte[] _CreateAlert (Alert alert)
		{
			var buffer = new BufferOffsetSize (2);
			buffer.Buffer [0] = (byte)alert.Level;
			buffer.Buffer [1] = (byte)alert.Description;

			return EncodeRecord (ContentType.Alert, buffer);
		}
Пример #21
0
        } // SetUnmanagedStructures()

        internal void SetUnmanagedStructures(
            BufferOffsetSize[] buffers,
            SocketFlags socketFlags) {

                //
                // create the event handle
                //
                m_OverlappedEvent = new AutoResetEvent(false);

                //
                // fill in the overlapped structure with the event handle.
                //
                Marshal.WriteIntPtr(
                    m_UnmanagedBlob,
                    Win32.OverlappedhEventOffset,
                    m_OverlappedEvent.Handle );

            //
            // Fill in Buffer Array structure that will be used for our send/recv Buffer
            //
            m_WSABuffers = new WSABuffer[buffers.Length];
            m_GCHandles = new GCHandle[buffers.Length];
            for (int i = 0; i < buffers.Length; i++) {
                m_GCHandles[i] = GCHandle.Alloc(buffers[i].Buffer, GCHandleType.Pinned);
                m_WSABuffers[i].Length = buffers[i].Size;
                m_WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffers[i].Buffer, buffers[i].Offset);
            }
            //
            // fill in flags if we use it.
            //
            m_Flags = socketFlags;
        }
Пример #22
0
        //
        // Combined [....]/async write method. For [....] case asyncRequest==null
        //
        private void ProcessWrite(BufferOffsetSize[] buffers, SplitWriteAsyncProtocolRequest asyncRequest)
        {
            foreach (BufferOffsetSize buffer in buffers)
            {
                ValidateParameters(buffer.Buffer, buffer.Offset, buffer.Size);
            }

            if (Interlocked.Exchange(ref _NestedWrite, 1) == 1)
            {
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginWrite":"Write"), "write"));
            }

            bool failed = false;
            try
            {
                SplitWritesState splitWrite = new SplitWritesState(buffers);
                if (asyncRequest != null)
                    asyncRequest.SetNextRequest(splitWrite, _ResumeAsyncWriteCallback);

                StartWriting(splitWrite, asyncRequest);
            }
            catch (Exception e)
            {
                _SslState.FinishWrite();

                failed = true;
                if (e is IOException) {
                    throw;
                }
                throw new IOException(SR.GetString(SR.net_io_write), e);
            }
            finally
            {
                if (asyncRequest == null || failed)
                {
                    _NestedWrite = 0;
                }
            }
        }
Пример #23
0
        //
        // Performs encryption of an array of buffers, proceeds buffer by buffer, if the individual
        // buffer size exceeds a SSL limit of SecureChannel.MaxDataSize,the buffers are then split into smaller ones.
        // Returns the same array that is encrypted or a new array of encrypted buffers.
        //
        private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload)
        {

            List<BufferOffsetSize> arrayList = null;
            SecurityStatus status = SecurityStatus.OK;

            foreach(BufferOffsetSize buffer in buffers)
            {
                int chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize);

                byte[] outBuffer = null;
                int    outSize;

                status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize);
                if (status != SecurityStatus.OK)
                    break;

                if (chunkBytes != buffer.Size || arrayList != null)
                {
                    if (arrayList == null)
                    {
                        arrayList = new List<BufferOffsetSize>(buffers.Length * (buffer.Size/chunkBytes+1));
                        if (lastHandshakePayload != null)
                            arrayList.Add(new BufferOffsetSize(lastHandshakePayload, false));

                        foreach(BufferOffsetSize oldBuffer in buffers)
                        {
                            if (oldBuffer == buffer)
                                break;
                            arrayList.Add(oldBuffer);
                        }
                    }
                    arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false));
                    while ((buffer.Size-=chunkBytes) != 0)
                    {
                        buffer.Offset += chunkBytes;
                        chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize);
                        outBuffer = null;
                        status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize);
                        if (status != SecurityStatus.OK)
                            break;
                        arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false));
                    }
                }
                else
                {
                    buffer.Buffer = outBuffer;
                    buffer.Offset = 0;
                    buffer.Size   = outSize;
                }
                if (status != SecurityStatus.OK)
                    break;
            }

            if (status != SecurityStatus.OK)
            {
                //
                ProtocolToken message = new ProtocolToken(null, status);
                throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException());
            }

            if (arrayList != null)
                buffers = arrayList.ToArray();
            else if (lastHandshakePayload != null)
            {
                BufferOffsetSize[] result = new BufferOffsetSize[buffers.Length+1];
                Array.Copy(buffers, 0, result, 1, buffers.Length);
                result[0] = new BufferOffsetSize(lastHandshakePayload, false);
                buffers = result;
            }

            return buffers;
        }
Пример #24
0
		int ProcessReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, LazyAsyncResult lazyResult)
		{
			if (userBuffer == null || userBuffer.Buffer == null)
				throw new ArgumentNullException ("buffer");
			if (userBuffer.Offset < 0)
				throw new ArgumentOutOfRangeException ("offset");
			if (userBuffer.Size < 0 || userBuffer.Offset + userBuffer.Size > userBuffer.Buffer.Length)
				throw new ArgumentOutOfRangeException ("count");

			CheckThrow (true);

			var name = internalBuffer == readBuffer ? "read" : "write";
			Debug ("ProcessReadOrWrite: {0} {1}", name, userBuffer);

			var asyncRequest = new AsyncProtocolRequest (this, lazyResult, userBuffer);
			return StartOperation (ref nestedRequest, ref internalBuffer, operation, asyncRequest, name);
		}
Пример #25
0
        private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload)
        {
            List <BufferOffsetSize> list = null;
            SecurityStatus          oK   = SecurityStatus.OK;

            foreach (BufferOffsetSize size in buffers)
            {
                int    num2;
                int    count     = Math.Min(size.Size, this._SslState.MaxDataSize);
                byte[] outBuffer = null;
                oK = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2);
                if (oK != SecurityStatus.OK)
                {
                    break;
                }
                if ((count != size.Size) || (list != null))
                {
                    if (list == null)
                    {
                        list = new List <BufferOffsetSize>(buffers.Length * ((size.Size / count) + 1));
                        if (lastHandshakePayload != null)
                        {
                            list.Add(new BufferOffsetSize(lastHandshakePayload, false));
                        }
                        foreach (BufferOffsetSize size2 in buffers)
                        {
                            if (size2 == size)
                            {
                                break;
                            }
                            list.Add(size2);
                        }
                    }
                    list.Add(new BufferOffsetSize(outBuffer, 0, num2, false));
                    while ((size.Size -= count) != 0)
                    {
                        size.Offset += count;
                        count        = Math.Min(size.Size, this._SslState.MaxDataSize);
                        oK           = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2);
                        if (oK != SecurityStatus.OK)
                        {
                            break;
                        }
                        list.Add(new BufferOffsetSize(outBuffer, 0, num2, false));
                    }
                }
                else
                {
                    size.Buffer = outBuffer;
                    size.Offset = 0;
                    size.Size   = num2;
                }
                if (oK != SecurityStatus.OK)
                {
                    break;
                }
            }
            if (oK != SecurityStatus.OK)
            {
                ProtocolToken token = new ProtocolToken(null, oK);
                throw new IOException(SR.GetString("net_io_encrypt"), token.GetException());
            }
            if (list != null)
            {
                buffers = list.ToArray();
                return(buffers);
            }
            if (lastHandshakePayload != null)
            {
                BufferOffsetSize[] destinationArray = new BufferOffsetSize[buffers.Length + 1];
                Array.Copy(buffers, 0, destinationArray, 1, buffers.Length);
                destinationArray[0] = new BufferOffsetSize(lastHandshakePayload, false);
                buffers             = destinationArray;
            }
            return(buffers);
        }
Пример #26
0
        int StartOperation(ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize internalBuffer, AsyncOperation operation, AsyncProtocolRequest asyncRequest, string name)
        {
            if (Interlocked.CompareExchange (ref nestedRequest, asyncRequest, null) != null)
                throw new InvalidOperationException ("Invalid nested call.");

            bool failed = false;
            try {
                internalBuffer.Reset ();
                asyncRequest.StartOperation (operation);
                return asyncRequest.UserResult;
            } catch (Exception e) {
                failed = true;
                if (e is IOException)
                    throw;
                throw new IOException (name + " failed", e);
            } finally {
                if (asyncRequest.UserAsyncResult == null || failed) {
                    internalBuffer.Reset ();
                    nestedRequest = null;
                }
            }
        }
Пример #27
0
		int InternalRead (AsyncProtocolRequest asyncRequest, BufferOffsetSize internalBuffer, byte[] buffer, int offset, int size, out bool wantMore)
		{
			if (asyncRequest == null)
				throw new InvalidOperationException ();

			Debug ("InternalRead: {0} {1} {2}", internalBuffer, offset, size);

			/*
			 * One of Apple's native functions wants to read 'size' bytes of data.
			 *
			 * First, we check whether we already have enough in the internal buffer.
			 *
			 * If the internal buffer is empty (it will be the first time we're called), we save
			 * the amount of bytes that were requested and return 'SslStatus.WouldBlock' to our
			 * native caller.  This native function will then return this code to managed code,
			 * where we read the requested amount of data into the internal buffer, then call the
			 * native function again.
			 */
			if (internalBuffer.Size == 0 && !internalBuffer.Complete) {
				Debug ("InternalRead #1: {0} {1}", internalBuffer.Offset, internalBuffer.TotalBytes);
				internalBuffer.Offset = internalBuffer.Size = 0;
				asyncRequest.RequestRead (size);
				wantMore = true;
				return 0;
			}

			/*
			 * The second time we're called, the native buffer will contain the exact amount of data that the
			 * previous call requested from us, so we should be able to return it all here.  However, just in
			 * case that Apple's native function changed its mind, we can also return less.
			 *
			 * In either case, if we have any data buffered, then we return as much of it as possible - if the
			 * native code isn't satisfied, then it will call us again to request more.
			 */
			var len = System.Math.Min (internalBuffer.Size, size);
			Buffer.BlockCopy (internalBuffer.Buffer, internalBuffer.Offset, buffer, offset, len);
			internalBuffer.Offset += len;
			internalBuffer.Size -= len;
			wantMore = !internalBuffer.Complete && len < size;
			return len;
		}
Пример #28
0
        protected override int Decrypt(DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output)
        {
            if ((input.Size % BlockSize) != 0)
            {
                return(-1);
            }
            if (input.Size < MinExtraEncryptedBytes)
            {
                return(-1);
            }

            var plen = DecryptRecord(d, input, output);

            if (plen <= 0)
            {
                return(-1);
            }

            var padlen = output.Buffer [output.Offset + plen - 1];

                        #if DEBUG_FULL
            if (Cipher.EnableDebugging)
            {
                DebugHelper.WriteLine("DECRYPT: {0} {1} {2}", input.Size, plen, padlen);
                DebugHelper.WriteBuffer("DECRYPTED", output.Buffer, output.Offset, plen);
            }
                        #endif

            /*
             * VERY IMPORTANT:
             *
             * The Compiler and JIT *** MUST NOT *** optimize the following block of code.
             *
             * It is essential that the dummy checks and dummy calls be kept in place.
             * Also do not put any debugging code into that region as it would mess up with
             * the timing.
             *
             */

            #region The following block of code *** MUST NOT *** be optimized in any way

            if (MacSize + padlen + 1 > plen)
            {
                // Invalid padding: plaintext is not long enough.

                // First run a loop as if there were 256 bytes of padding, with a dummy check.
                int ok = -1;
                for (int i = 0; i < 256; i++)
                {
                    if (output.Buffer [i % output.Size] != padlen)
                    {
                        ok--;
                    }
                }

                // Now assume there's no padding, compute the MAC over the entire buffer.
                var first      = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize);
                var invalidMac = ComputeRecordMAC(contentType, first);

                // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
                ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
                return(ok);
            }
            else
            {
                int ok           = 0;
                var resultLength = plen - padlen - MacSize - 1;
                for (int i = 0; i < padlen; i++)
                {
                    if (output.Buffer [output.Offset + resultLength + MacSize + i] != padlen)
                    {
                        ok--;
                    }
                }

                var dummyOk  = ok;
                var dummyLen = 256 - padlen - 1;
                for (int i = 0; i < dummyLen; i++)
                {
                    if (output.Buffer [i % output.Size] != padlen)
                    {
                        dummyOk--;
                    }
                }

                if (ok < 0)
                {
                    // Now assume there's no padding, compute the MAC over the entire buffer.
                    var first      = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize);
                    var invalidMac = ComputeRecordMAC(contentType, first);

                    // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
                    ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
                    return(ok);
                }
                else
                {
                    var first    = new BufferOffsetSize(output.Buffer, output.Offset, resultLength);
                    var checkMac = ComputeRecordMAC(contentType, first);

                    var L1 = 13 + plen - MacSize;
                    var L2 = 13 + plen - padlen - 1 - MacSize;

                    var additional = ((L1 - 55) / 64) - ((L2 - 55) / 64);
                    if (additional > 0)
                    {
                        var algorithm = HMac.CreateHash(Cipher.HashAlgorithmType);
                        for (int i = 0; i < additional; i++)
                        {
                            algorithm.TransformBlock(input.Buffer, input.Offset, BlockSize, null, 0);
                        }
                    }

                    ok += TlsBuffer.ConstantTimeCompare(checkMac, 0, checkMac.Length, output.Buffer, output.Offset + resultLength, MacSize);
                    if (ok == 0)
                    {
                        ok = resultLength;
                    }
                    return(ok);
                }
            }

            #endregion
        }
Пример #29
0
		public IBufferOffsetSize Encrypt (ContentType contentType, IBufferOffsetSize data)
		{
			var output = new BufferOffsetSize (GetEncryptedSize (data.Size));
			var ret = Encrypt (contentType, data, output);
			output.TruncateTo (ret);
			return output;
		}
 /// <devdoc>
 ///    <para>
 ///       Due to Winsock restrictions
 ///       If on Win9x platforms and the number of buffers are more than 16, performs
 ///         concatenation of the buffers, so that we have 16 buffers.
 ///    </para>
 /// </devdoc>
 private BufferOffsetSize[] ConcatenateBuffersOnWin9x(BufferOffsetSize[] buffers) {
     return buffers;
 }
Пример #31
0
 //
 //
 internal void Write(BufferOffsetSize[] buffers)
 {
     ProcessWrite(buffers, null);
 }
Пример #32
0
        internal virtual IAsyncResult UnsafeBeginMultipleWrite(
            BufferOffsetSize[] buffers,
            AsyncCallback callback,
            Object state)
        {
#if DEBUG
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "NetworkStream#" + ValidationHelper.HashString(this) + "::BeginMultipleWrite");
            using (GlobalLog.SetThreadKind(ThreadKinds.Async)) {
#endif

            //
            // parameter validation
            //
            if (buffers == null) {
                throw new ArgumentNullException("buffers");
            }

            Socket chkStreamSocket = m_StreamSocket;
            if(chkStreamSocket == null) {
                throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
            }

            try {

                //
                // call BeginMultipleSend on the Socket.
                //
                IAsyncResult asyncResult =
                    chkStreamSocket.UnsafeBeginMultipleSend(
                        buffers,
                        SocketFlags.None,
                        callback,
                        state);

                return asyncResult;
            }
            catch (Exception exception) {

                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
                    throw;
	            }

                //
                // some sort of error occured on the socket call,
                // set the SocketException as InnerException and throw
                //
                throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
            }
#if DEBUG
            }
#endif
        }
Пример #33
0
 //
 //  Assumes that InnerStream type == typeof(NetworkStream)
 //
 internal IAsyncResult BeginWrite(BufferOffsetSize[] buffers, AsyncCallback asyncCallback, object asyncState)
 {
     LazyAsyncResult lazyResult = new LazyAsyncResult(this, asyncState, asyncCallback);
     SplitWriteAsyncProtocolRequest asyncRequest = new SplitWriteAsyncProtocolRequest(lazyResult);
     ProcessWrite(buffers, asyncRequest);
     return lazyResult;
 }
Пример #34
0
 public BufferList(BufferOffsetSize[] buffers)
 {
     _buffers = buffers;
 }
Пример #35
0
        //
        // Combined [....]/async write method. For [....] case asyncRequest==null
        //
        private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            if (_SslState.LastPayload != null)
            {
                //
                // !!! LastPayload Only used in TlsStream  for HTTP and it needs re-work for a general case !!!
                //
                BufferOffsetSize[] buffers = new BufferOffsetSize[1];
                buffers[0] = new BufferOffsetSize(buffer, offset, count, false);
                if (asyncRequest != null)
                    ProcessWrite(buffers, new SplitWriteAsyncProtocolRequest(asyncRequest.UserAsyncResult));
                else
                    ProcessWrite(buffers, null);
                return;
            }

            ValidateParameters(buffer, offset, count);

            if (Interlocked.Exchange(ref _NestedWrite, 1) == 1)
            {
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginWrite":"Write"), "write"));
            }

            bool failed = false;
            try
            {
                StartWriting(buffer, offset, count, asyncRequest);
            }
            catch (Exception e)
            {
                _SslState.FinishWrite();

                failed = true;
                if (e is IOException) {
                    throw;
                }
                throw new IOException(SR.GetString(SR.net_io_write), e);
            }
            finally
            {
                if (asyncRequest == null || failed)
                {
                    _NestedWrite = 0;
                }
            }
        }
Пример #36
0
		public bool ProcessHandshakeMessage (HandshakeType type, TlsBuffer incoming, out SecurityStatus status)
		{
			if (HasPendingOutput && type != HandshakeType.HelloRequest)
				throw new TlsException (AlertDescription.InternalError);
			if (!VerifyMessage (type)) {
				if (type == HandshakeType.HelloRequest) {
					status = SecurityStatus.ContinueNeeded;
					return false;
				}
				throw new TlsException (AlertDescription.UnexpectedMessage);
			}

			var incomingBuffer = new BufferOffsetSize (incoming.Buffer, incoming.Position - 4, incoming.Remaining + 4);

			var startPosition = incoming.Position - 4;
			var message = CreateMessage (type, incoming);
			incoming.Position = startPosition;

			#if DEBUG_FULL
			if (Context.EnableDebugging)
				DebugHelper.WriteLine ("ProcessMessage: {0} {1} {2}", GetType ().Name, Context.IsServer, type);
			#endif

			#if INSTRUMENTATION
			if (State == NegotiationState.InitialServerConnection && Context.HasInstrument (HandshakeInstrumentType.CloseServerConnection)) {
				DebugHelper.WriteLine ("Instrumentation requested to close server connection.");
				status = SecurityStatus.InvalidHandle;
				return true;
			}
			#endif

 			var result = HandleMessage (message);

			switch (result) {
			case MessageStatus.CredentialsNeeded:
				status = SecurityStatus.CredentialsNeeded;
				return false;

			case MessageStatus.Finished:
				hasPendingOutput = true;
				if (Context.IsServer)
					Context.HandshakeParameters.HandshakeMessages.Add (message, incomingBuffer);
				status = SecurityStatus.OK;
				return true;

			case MessageStatus.IgnoreMessage:
				status = SecurityStatus.ContinueNeeded;
				return false;

			case MessageStatus.Renegotiate:
				hasPendingOutput = true;
				if (message.Type != HandshakeType.HelloRequest)
					Context.HandshakeParameters.HandshakeMessages.Add (message, incomingBuffer);
				status = SecurityStatus.ContinueNeeded;
				return true;

			case MessageStatus.GenerateOutput:
				hasPendingOutput = true;
				Context.HandshakeParameters.HandshakeMessages.Add (message, incomingBuffer);
				status = SecurityStatus.ContinueNeeded;
				return true;

			case MessageStatus.ContinueNeeded:
				Context.HandshakeParameters.HandshakeMessages.Add (message, incomingBuffer);
				status = SecurityStatus.ContinueNeeded;
				return false;

			default:
				throw new InvalidOperationException ();
			}
		}
Пример #37
0
		static void EncodeRecord_internal (TlsProtocolCode protocol, ContentType contentType, CryptoParameters crypto, IBufferOffsetSize buffer, TlsStream output,
			int fragmentSize = MAX_FRAGMENT_SIZE)
		{
			var maxExtraBytes = crypto != null ? crypto.MaxExtraEncryptedBytes : 0;

			var offset = buffer.Offset;
			var remaining = buffer.Size;

			#if !INSTRUMENTATION
			fragmentSize = MAX_FRAGMENT_SIZE;
			#endif

			do {
				BufferOffsetSize fragment;

				var encryptedSize = crypto != null ? crypto.GetEncryptedSize (remaining) : remaining;
				if (encryptedSize <= fragmentSize)
					fragment = new BufferOffsetSize (buffer.Buffer, offset, remaining);
				else {
					fragment = new BufferOffsetSize (buffer.Buffer, offset, fragmentSize - maxExtraBytes);
					encryptedSize = crypto != null ? crypto.GetEncryptedSize (fragment.Size) : fragment.Size;
				}

				// Write tls message
				output.Write ((byte)contentType);
				output.Write ((short)protocol);
				output.Write ((short)encryptedSize);

				if (crypto != null) {
					output.MakeRoom (encryptedSize);
					var ret = crypto.Encrypt (contentType, fragment, output.GetRemaining ());
					output.Position += ret;
				} else {
					output.Write (fragment.Buffer, fragment.Offset, fragment.Size);
				}

				offset += fragment.Size;
				remaining -= fragment.Size;
			} while (remaining > 0);
		}
            private static IAsyncResult BeginMultipleWrite(IList<ArraySegment<byte>> sendBuffers, AsyncCallback callback, object asyncState)
            {
                Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL.");
                Contract.Assert(asyncState != null, "'asyncState' MUST NOT be NULL.");
                WebSocketConnection connection = asyncState as WebSocketConnection;
                Contract.Assert(connection != null, "'connection' MUST NOT be NULL.");

                BufferOffsetSize[] buffers = new BufferOffsetSize[sendBuffers.Count];
                
                for (int index = 0; index < sendBuffers.Count; index++)
                {
                    ArraySegment<byte> sendBuffer = sendBuffers[index];
                    buffers[index] = new BufferOffsetSize(sendBuffer.Array, sendBuffer.Offset, sendBuffer.Count, false);
                }

                WebSocketHelpers.ThrowIfConnectionAborted(connection.m_InnerStream, false);
                return connection.m_InnerStream.NetworkStream.BeginMultipleWrite(buffers, callback, asyncState);
            }
Пример #39
0
        /// <devdoc>
        ///    <para>
        ///       Performs a [....] Write of an array of buffers.
        ///    </para>
        /// </devdoc>
        internal virtual void MultipleWrite(BufferOffsetSize[] buffers)
        {
            GlobalLog.ThreadContract(ThreadKinds.Sync, "NetworkStream#" + ValidationHelper.HashString(this) + "::MultipleWrite");

            //
            // parameter validation
            //
            if (buffers == null) {
                throw new ArgumentNullException("buffers");
            }

            Socket chkStreamSocket = m_StreamSocket;
            if(chkStreamSocket == null) {
                throw new IOException(SR.GetString(SR.net_io_writefailure, SR.GetString(SR.net_io_connectionclosed)));
            }

            try {

                chkStreamSocket.MultipleSend(
                    buffers,
                    SocketFlags.None);

            }
            catch (Exception exception) {
                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {                                       
                    throw;
	            }

                //
                // some sort of error occured on the socket call,
                // set the SocketException as InnerException and throw
                //
                throw new IOException(SR.GetString(SR.net_io_writefailure, exception.Message), exception);
            }
        }
Пример #40
0
		internal IAsyncResult UnsafeBeginMultipleSend (BufferOffsetSize[] buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
		{
			return BeginMultipleSend (buffers, socketFlags, callback, state);
		}
Пример #41
0
 public AsyncProtocolRequest(MobileAuthenticatedStream parent, LazyAsyncResult lazyResult, BufferOffsetSize userBuffer = null)
 {
     Parent = parent;
     UserAsyncResult = lazyResult;
     UserBuffer = userBuffer;
 }
Пример #42
0
		public IBufferOffsetSize Decrypt (ContentType contentType, IBufferOffsetSize input)
		{
			var output = new BufferOffsetSize (input.Size);
			var ret = Decrypt (contentType, input, output);
			output.TruncateTo (ret);
			return output;
		}
Пример #43
0
        public bool ProcessHandshakeMessage(HandshakeType type, TlsBuffer incoming, out SecurityStatus status)
        {
            if (HasPendingOutput && type != HandshakeType.HelloRequest)
            {
                throw new TlsException(AlertDescription.InternalError);
            }
            if (!VerifyMessage(type))
            {
                throw new TlsException(AlertDescription.UnexpectedMessage);
            }

            var incomingBuffer = new BufferOffsetSize(incoming.Buffer, incoming.Position - 4, incoming.Remaining + 4);

            var startPosition = incoming.Position - 4;
            var message       = CreateMessage(type, incoming);

            incoming.Position = startPosition;
                        #if FIXME
            incoming.Offset = incoming.Position;
                        #endif

                        #if DEBUG_FULL
            if (Context.EnableDebugging)
            {
                DebugHelper.WriteLine("ProcessMessage: {0} {1} {2}", GetType().Name, Context.IsServer, type);
            }
                        #endif

            var result = HandleMessage(message);

            switch (result)
            {
            case MessageStatus.CredentialsNeeded:
                status = SecurityStatus.CredentialsNeeded;
                return(false);

            case MessageStatus.Finished:
                hasPendingOutput = true;
                if (Context.IsServer)
                {
                    Context.HandshakeParameters.HandshakeMessages.Add(message, incomingBuffer);
                }
                status = SecurityStatus.OK;
                return(true);

            case MessageStatus.IgnoreMessage:
                status = SecurityStatus.ContinueNeeded;
                return(false);

            case MessageStatus.Renegotiate:
                hasPendingOutput = true;
                if (message.Type != HandshakeType.HelloRequest)
                {
                    Context.HandshakeParameters.HandshakeMessages.Add(message, incomingBuffer);
                }
                status = SecurityStatus.Renegotiate;
                return(true);

            case MessageStatus.GenerateOutput:
                hasPendingOutput = true;
                Context.HandshakeParameters.HandshakeMessages.Add(message, incomingBuffer);
                status = SecurityStatus.ContinueNeeded;
                return(true);

            case MessageStatus.ContinueNeeded:
                Context.HandshakeParameters.HandshakeMessages.Add(message, incomingBuffer);
                status = SecurityStatus.ContinueNeeded;
                return(false);

            default:
                throw new InvalidOperationException();
            }
        }
Пример #44
0
		protected override int Encrypt (DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output)
		{
			// Calculate message MAC
			byte[] mac = null;
			if (IsServer)
				mac = ComputeServerRecordMAC (contentType, input);
			else
				mac = ComputeClientRecordMAC (contentType, input);

			#if DEBUG_FULL
			if (Cipher.EnableDebugging)
				DebugHelper.WriteLine ("RECORD MAC", mac);
			#endif

			int plen;
			byte padLen;
			int totalLength = GetEncryptedSize (input.Size, out plen, out padLen);

			var totalOutput = new BufferOffsetSize (output.Buffer, output.Offset, totalLength);
			var outputWriter = new TlsBuffer (totalOutput);

			outputWriter.Position += HeaderSize;

			outputWriter.Write (input.Buffer, input.Offset, input.Size);
			outputWriter.Write (mac);

			for (int i = 0; i <= padLen; i++)
				outputWriter.Write (padLen);

			// Encrypt the message
			EncryptRecord (d, totalOutput);
			return totalLength;
		}
Пример #45
0
        //
        // Performs encryption of an array of buffers, proceeds buffer by buffer, if the individual
        // buffer size exceeds a SSL limit of SecureChannel.MaxDataSize,the buffers are then split into smaller ones.
        // Returns the same array that is encrypted or a new array of encrypted buffers.
        //
        private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload)
        {
            List <BufferOffsetSize> arrayList = null;
            SecurityStatus          status    = SecurityStatus.OK;

            foreach (BufferOffsetSize buffer in buffers)
            {
                int chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize);

                byte[] outBuffer = null;
                int    outSize;

                status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize);
                if (status != SecurityStatus.OK)
                {
                    break;
                }

                if (chunkBytes != buffer.Size || arrayList != null)
                {
                    if (arrayList == null)
                    {
                        arrayList = new List <BufferOffsetSize>(buffers.Length * (buffer.Size / chunkBytes + 1));
                        if (lastHandshakePayload != null)
                        {
                            arrayList.Add(new BufferOffsetSize(lastHandshakePayload, false));
                        }

                        foreach (BufferOffsetSize oldBuffer in buffers)
                        {
                            if (oldBuffer == buffer)
                            {
                                break;
                            }
                            arrayList.Add(oldBuffer);
                        }
                    }
                    arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false));
                    while ((buffer.Size -= chunkBytes) != 0)
                    {
                        buffer.Offset += chunkBytes;
                        chunkBytes     = Math.Min(buffer.Size, _SslState.MaxDataSize);
                        outBuffer      = null;
                        status         = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize);
                        if (status != SecurityStatus.OK)
                        {
                            break;
                        }
                        arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false));
                    }
                }
                else
                {
                    buffer.Buffer = outBuffer;
                    buffer.Offset = 0;
                    buffer.Size   = outSize;
                }
                if (status != SecurityStatus.OK)
                {
                    break;
                }
            }

            if (status != SecurityStatus.OK)
            {
                //
                ProtocolToken message = new ProtocolToken(null, status);
                throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException());
            }

            if (arrayList != null)
            {
                buffers = arrayList.ToArray();
            }
            else if (lastHandshakePayload != null)
            {
                BufferOffsetSize[] result = new BufferOffsetSize[buffers.Length + 1];
                Array.Copy(buffers, 0, result, 1, buffers.Length);
                result[0] = new BufferOffsetSize(lastHandshakePayload, false);
                buffers   = result;
            }

            return(buffers);
        }
Пример #46
0
		protected override int Decrypt (DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output)
		{
			if ((input.Size % BlockSize) != 0)
				return -1;
			if (input.Size < MinExtraEncryptedBytes)
				return -1;

			var plen = DecryptRecord (d, input, output);
			if (plen <= 0)
				return -1;

			var padlen = output.Buffer [output.Offset + plen - 1];
			#if DEBUG_FULL
			if (Cipher.EnableDebugging) {
				DebugHelper.WriteLine ("DECRYPT: {0} {1} {2}", input.Size, plen, padlen);
				DebugHelper.WriteBuffer ("DECRYPTED", output.Buffer, output.Offset, plen);
			}
			#endif

			/*
			 * VERY IMPORTANT:
			 * 
			 * The Compiler and JIT *** MUST NOT *** optimize the following block of code.
			 * 
			 * It is essential that the dummy checks and dummy calls be kept in place.
			 * Also do not put any debugging code into that region as it would mess up with
			 * the timing.
			 * 
			 */

			#region The following block of code *** MUST NOT *** be optimized in any way

			if (MacSize + padlen + 1 > plen) {
				// Invalid padding: plaintext is not long enough.

				// First run a loop as if there were 256 bytes of padding, with a dummy check.
				int ok = -1;
				for (int i = 0; i < 256; i++) {
					if (output.Buffer [i % output.Size] != padlen)
						ok--;
				}

				// Now assume there's no padding, compute the MAC over the entire buffer.
				var first = new BufferOffsetSize (output.Buffer, output.Offset, plen - MacSize);
				var invalidMac = ComputeRecordMAC (contentType, first);

				// Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
				ok += TlsBuffer.ConstantTimeCompare (invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
				return ok;
			} else {
				int ok = 0;
				var resultLength = plen - padlen - MacSize - 1;
				for (int i = 0; i < padlen; i++) {
					if (output.Buffer [output.Offset + resultLength + MacSize + i] != padlen)
						ok--;
				}

				var dummyOk = ok;
				var dummyLen = 256 - padlen - 1;
				for (int i = 0; i < dummyLen; i++) {
					if (output.Buffer [i % output.Size] != padlen)
						dummyOk--;
				}

				if (ok < 0) {
					// Now assume there's no padding, compute the MAC over the entire buffer.
					var first = new BufferOffsetSize (output.Buffer, output.Offset, plen - MacSize);
					var invalidMac = ComputeRecordMAC (contentType, first);

					// Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error.
					ok += TlsBuffer.ConstantTimeCompare (invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize);
					return ok;
				} else {
					var first = new BufferOffsetSize (output.Buffer, output.Offset, resultLength);
					var checkMac = ComputeRecordMAC (contentType, first);

					var L1 = 13 + plen - MacSize;
					var L2 = 13 + plen - padlen - 1 - MacSize;

					var additional = ((L1 - 55) / 64) - ((L2 - 55) / 64);
					if (additional > 0) {
						var algorithm = HMac.CreateHash (Cipher.HashAlgorithmType);
						for (int i = 0; i < additional; i++)
							algorithm.TransformBlock (input.Buffer, input.Offset, BlockSize, null, 0);
					}

					ok += TlsBuffer.ConstantTimeCompare (checkMac, 0, checkMac.Length, output.Buffer, output.Offset + resultLength, MacSize);
					if (ok == 0)
						ok = resultLength;
					return ok;
				}
			}

			#endregion
		}