Example #1
0
        public static bool TryGetFrame(ref ReadableBuffer buffer, out ReadableBuffer messageBuffer)
        {
            messageBuffer = default(ReadableBuffer);
            if (buffer.Length < 5)
            {
                return(false);
            }
            var frameType = buffer.ReadBigEndian <RecordType>();

            if (frameType != RecordType.Alert && frameType != RecordType.Application &&
                frameType != RecordType.Handshake)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, $"unknown frame type {frameType}");
            }
            var version = buffer.Slice(1).ReadBigEndian <ushort>();

            if (version < 0x0300 || version > 0x0400)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, $"The frame version was outside the range {version}");
            }
            var length = buffer.Slice(3).ReadBigEndian <ushort>();

            if (buffer.Length >= (length + RecordHeaderLength))
            {
                messageBuffer = buffer.Slice(0, length + RecordHeaderLength);
                buffer        = buffer.Slice(length + RecordHeaderLength);
                return(true);
            }
            return(false);
        }
Example #2
0
        public static void ReadServerHello(ReadableBuffer readable, IConnectionStateTls13 connectionState)
        {
            var    original = readable;
            ushort version, cipherCode;

            readable = readable.Slice(HandshakeProcessor.HandshakeHeaderSize);
            readable = readable.SliceBigEndian(out version);
            //skip random
            readable = readable.Slice(RandomLength);
            readable = readable.SliceBigEndian(out cipherCode);
            connectionState.CipherSuite = connectionState.CryptoProvider.GetCipherSuiteFromCode(cipherCode, connectionState.Version);
            if (connectionState.CipherSuite == null)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "Could not get a cipher suite during server hello");
            }
            connectionState.StartHandshakeHash(original);
            readable = BufferExtensions.SliceVector <ushort>(ref readable);
            ExtensionType ext;

            readable = readable.SliceBigEndian(out ext);
            if (ext != ExtensionType.key_share)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "There was no keyshare on the server hello");
            }
            readable = BufferExtensions.SliceVector <ushort>(ref readable);
            NamedGroup group;

            readable = readable.SliceBigEndian(out group);
            if (group != connectionState.KeyShare.NamedGroup)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "The named group didn't match the keyshare during server hello");
            }
            readable = BufferExtensions.SliceVector <ushort>(ref readable);
            connectionState.KeyShare.SetPeerKey(readable);
        }
Example #3
0
        public override RecordState ReadRecord(ref ReadableBuffer buffer, out ReadableBuffer messageBuffer)
        {
            messageBuffer = default;
            if (buffer.Length < _minimumMessageSize)
            {
                return(RecordState.Incomplete);
            }
            var header = buffer.Slice(0, _minimumMessageSize).ToSpan().Read <RecordHeader>();

            if (buffer.Length < header.Length + _minimumMessageSize)
            {
                return(RecordState.Incomplete);
            }
            _currentRecordType = header.RecordType;
            if (_connection?.ReadKey == null)
            {
                messageBuffer = buffer.Slice(_minimumMessageSize, header.Length);
                buffer        = buffer.Slice(messageBuffer.End);
            }
            else
            {
                messageBuffer = buffer.Slice(_minimumMessageSize, header.Length);
                buffer        = buffer.Slice(messageBuffer.End);
                _connection.ReadKey.Decrypt(ref messageBuffer, header.RecordType, header.Version);
            }
            return(RecordState.Record);
        }
Example #4
0
        protected override void WriteRecords(ref ReadableBuffer buffer, ref WritableBuffer writer, RecordType recordType)
        {
            ReadableBuffer append;

            while (buffer.Length > 0)
            {
                append = buffer.Slice(0, Math.Min(_maxMessageSize, buffer.Length));
                buffer = buffer.Slice(append.End);
                var recordHeader = new RecordHeader()
                {
                    RecordType = recordType,
                    Length     = (ushort)append.Length,
                    Version    = _recordVersion
                };
                writer.Ensure(_minimumMessageSize);
                if (_connection?.WriteKey != null)
                {
                    recordHeader.Length += (ushort)(8 + _connection.WriteKey.Overhead);
                }
                writer.Buffer.Span.Write(recordHeader);
                writer.Advance(_minimumMessageSize);
                if (_connection?.WriteKey != null)
                {
                    _connection.WriteKey.Encrypt(ref writer, append, recordType, _recordVersion);
                }
                else
                {
                    writer.Append(append);
                }
            }
        }
Example #5
0
        public static ReadableBuffer SliceVector <[Primitive] T>(ref ReadableBuffer buffer) where T : struct
        {
            uint length = 0;

            if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
            {
                length = buffer.ReadBigEndian <byte>();
                buffer = buffer.Slice(sizeof(byte));
            }
            else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(short))
            {
                length = buffer.ReadBigEndian <ushort>();
                buffer = buffer.Slice(sizeof(ushort));
            }
            else if (typeof(T) == typeof(uint) || typeof(T) == typeof(int))
            {
                length = buffer.ReadBigEndian <uint>();
                buffer = buffer.Slice(sizeof(uint));
            }
            else
            {
                Internal.ExceptionHelper.ThrowException(new InvalidCastException($"The type {typeof(T)} is not a primitave integer type"));
            }
            var returnBuffer = buffer.Slice(0, (int)length);

            buffer = buffer.Slice(returnBuffer.End);
            return(returnBuffer);
        }
Example #6
0
        public unsafe void Decrypt(ref ReadableBuffer messageBuffer)
        {
            var tag = stackalloc byte[_overhead];

            messageBuffer.Slice(messageBuffer.Length - _overhead).CopyTo(new Span <byte>(tag, _overhead));
            messageBuffer = messageBuffer.Slice(0, messageBuffer.Length - _overhead);

            ThrowOnError(EVP_CipherInit_ex(_ctx, _cipherType, IntPtr.Zero, (void *)_keyPointer, (void *)_ivPointer, (int)KeyMode.Decryption));
            ThrowOnError(EVP_CIPHER_CTX_ctrl(_ctx, EVP_CIPHER_CTRL.EVP_CTRL_GCM_SET_TAG, _overhead, tag));
            int outLength;

            foreach (var b in messageBuffer)
            {
                if (b.Length > 0)
                {
                    GCHandle handle;
                    var      ptr = b.GetPointer(out handle);
                    outLength = b.Length;
                    ThrowOnError(EVP_CipherUpdate(_ctx, ptr, ref outLength, ptr, outLength));
                    if (outLength != b.Length)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
            outLength = 0;
            ThrowOnError(EVP_CipherFinal_ex(_ctx, null, ref outLength));
            IncrementSequence();
        }
Example #7
0
        public static string ReadString(ref ReadableBuffer buffer, out bool compressed)
        {
            int header = buffer.Peek();

            if (header < 0)
            {
                ThrowEndOfStreamException();
            }

            compressed = (header & 0x80) != 0;
            buffer     = buffer.Slice(1);
            int    len = checked ((int)ReadUInt64(ref buffer, header, 7));
            string result;

            if (compressed)
            {
                result = HuffmanCode.ReadString(buffer.Slice(0, len));
            }
            else
            {
                result = buffer.Slice(0, len).GetAsciiString();
            }

            buffer = buffer.Slice(len);
            return(result);
        }
Example #8
0
 private static void RemovePadding(ref ReadableBuffer buffer)
 {
     while (buffer.Slice(buffer.Length - 1).Peek() == 0)
     {
         buffer = buffer.Slice(0, buffer.Length - 1);
     }
 }
Example #9
0
    static bool FullRequestRb()
    {
        ReadableBuffer buffer        = ReadableBuffer.Create(s_plaintextTechEmpowerRequestBytes);
        var            parser        = new HttpParser();
        var            request       = new Request();
        int            consumedBytes = 0;
        ReadCursor     examined;
        ReadCursor     consumed = buffer.Start;
        bool           success  = true;

        foreach (var iteration in Benchmark.Iterations)
        {
            using (iteration.StartMeasurement()) {
                for (int i = 0; i < Benchmark.InnerIterationCount; i++)
                {
                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);
                }
            }
        }

        return(success);
    }
Example #10
0
        public static ReadableBuffer SliceVector24Bit(ref ReadableBuffer buffer)
        {
            var length       = buffer.ReadBigEndian24bit();
            var returnBuffer = buffer.Slice(3, length);

            buffer = buffer.Slice(returnBuffer.End);
            return(returnBuffer);
        }
Example #11
0
        public unsafe void Decrypt(ref ReadableBuffer messageBuffer)
        {
            var tag = stackalloc byte[_overhead];

            messageBuffer.Slice(messageBuffer.Length - _overhead).CopyTo(new Span <byte>(tag, _overhead));
            messageBuffer = messageBuffer.Slice(0, messageBuffer.Length - _overhead);

            throw new NotImplementedException();
        }
Example #12
0
        public void DecryptSession(ref ReadableBuffer buffer, IConnectionStateTls13 state)
        {
            var nounce = buffer.Slice(0, 12).ToArray();

            buffer = buffer.Slice(12);
            ushort cipherCode, version;

            buffer            = buffer.SliceBigEndian(out cipherCode);
            buffer            = buffer.SliceBigEndian(out version);
            state.CipherSuite = state.CryptoProvider.GetCipherSuiteFromCode(cipherCode, state.Version);
            state.KeySchedule = new KeySchedule13(state, state.Listener.KeyScheduleProvider.BufferPool, buffer);
        }
Example #13
0
        public static void ReadExtensionListTls(ref ReadableBuffer buffer, IConnectionState connectionState)
        {
            var            listLength          = buffer.ReadBigEndian <ushort>();
            ReadableBuffer signatureAlgoBuffer = default(ReadableBuffer);

            buffer = buffer.Slice(sizeof(ushort));
            if (buffer.Length < listLength)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, "The extension list is not as long as the header says");
            }
            var currentbuffer = buffer.Slice(0, listLength);

            buffer = buffer.Slice(currentbuffer.End);
            while (currentbuffer.Length > 3)
            {
                var extensionType   = currentbuffer.ReadBigEndian <ExtensionType>();
                var extensionLength = currentbuffer.Slice(sizeof(ExtensionType)).ReadBigEndian <ushort>();
                currentbuffer = currentbuffer.Slice(sizeof(ExtensionType) + sizeof(ushort));
                if (currentbuffer.Length < extensionLength)
                {
                    Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, $"The extension of type {extensionType} is too long for the remaining buffer");
                }
                var extensionBuffer = currentbuffer.Slice(0, extensionLength);
                currentbuffer = currentbuffer.Slice(extensionLength);
                switch (extensionType)
                {
                case ExtensionType.server_name:
                    ReadServerName(extensionBuffer, connectionState);
                    break;

                //case ExtensionType.signature_algorithms:
                //    signatureAlgoBuffer = extensionBuffer;
                //    break;
                case ExtensionType.supported_groups:
                    if (connectionState.CipherSuite.ExchangeType == KeyExchange.KeyExchangeType.Ecdhe)
                    {
                        connectionState.CryptoProvider.GetKeyshareFromNamedGroups(extensionBuffer);
                    }
                    break;

                case ExtensionType.renegotiation_info:
                    ReadRenegotiationInfo(extensionBuffer, connectionState);
                    break;
                }
            }
            //Wait until the end to check the signature, here we select the
            //certificate and this could depend on the server name indication
            //as well as the trusted CA roots.
            if (signatureAlgoBuffer.Length != 0)
            {
                ReadSignatureScheme(signatureAlgoBuffer, connectionState);
            }
        }
Example #14
0
            private void ParseExtension(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
            {
                // Chunk-extensions not currently parsed
                // Just drain the data
                consumed = buffer.Start;
                examined = buffer.Start;

                do
                {
                    ReadCursor extensionCursor;
                    if (ReadCursorOperations.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1)
                    {
                        // End marker not found yet
                        consumed = buffer.End;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(buffer.Length);
                        return;
                    }
                    ;

                    var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;

                    var sufixBuffer = buffer.Slice(extensionCursor);
                    if (sufixBuffer.Length < 2)
                    {
                        consumed = extensionCursor;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive);
                        return;
                    }

                    sufixBuffer = sufixBuffer.Slice(0, 2);
                    var sufixSpan = sufixBuffer.ToSpan();

                    if (sufixSpan[1] == '\n')
                    {
                        // We consumed the \r\n at the end of the extension, so switch modes.
                        _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer;

                        consumed = sufixBuffer.End;
                        examined = sufixBuffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
                    }
                    else
                    {
                        // Don't consume suffixSpan[1] in case it is also a \r.
                        buffer   = buffer.Slice(charsToByteCRExclusive + 1);
                        consumed = extensionCursor;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 1);
                    }
                } while (_mode == Mode.Extension);
            }
Example #15
0
        public static ulong ReadUInt64(ref ReadableBuffer buffer, int firstByte, int n)
        {
            if (n < 0 || n > 8)
            {
                throw new ArgumentOutOfRangeException(nameof(n));
            }
            int mask   = ~(~0 << n);
            int prefix = firstByte & mask;

            if (prefix != mask)
            {
                return((ulong)prefix); // short value encoded directly
            }
            ulong value = 0;
            int   shift = 0, nextByte;

            for (int i = 0; i < 9; i++)
            {
                nextByte = buffer.Peek();
                if (nextByte < 0)
                {
                    ThrowEndOfStreamException();
                }
                buffer = buffer.Slice(1);
                value |= ((ulong)nextByte & 0x7F) << shift;

                if ((nextByte & 0x80) == 0)
                {
                    // lack of continuation bit
                    return(value + (ulong)mask);
                }
                shift += 7;
            }
            switch (nextByte = buffer.Peek())
            {
            case 0:
            case 1:
                // note: lack of continuation bit (or anything else)
                buffer = buffer.Slice(1);
                value |= ((ulong)nextByte & 0x7F) << shift;
                return(value + (ulong)mask);

            default:
                if (nextByte < 0)
                {
                    ThrowEndOfStreamException();
                }
                // 7*9=63, so max 9 groups of 7 bits plus either 0 or 1;
                // after that: we've overflown
                throw new OverflowException();
            }
        }
        public static bool HandleMessage(ref ReadableBuffer reader)
        {
            if (reader.Length < 4)
            {
                return(false);
            }

            var messageLength = reader.ReadBigEndian <ushort>();

            if (reader.Length < (messageLength + 4))
            {
                return(false);
            }
            messageLength = reader.ReadBigEndian <ushort>();
            reader        = reader.Slice(2);
            var messageType = (MessageTypes)reader.ReadBigEndian <ushort>();

            var messageBuff = reader.Slice(2, messageLength);

            switch (messageType)
            {
            case MessageTypes.LoginAck:
                try
                {
                    var md = new LoginResponse(ref messageBuff);
                    ///Fire off to low priority queue because it's not very important
                }
                catch (Exception ex)
                {
                    errorCount++;
                    Console.WriteLine("Number of errors" + errorCount);
                }
                break;

            case MessageTypes.SomeDataUpdate:
                try
                {
                    var md = new SomeDataUpdate(ref messageBuff);
                    ///Fire off to very important queue as its realtime
                }
                catch (Exception ex)
                {
                    errorCount++;
                    Console.WriteLine("Number of errors" + errorCount);
                }
                break;
            }


            return(true);
        }
Example #17
0
        private unsafe void TestIndexOfWorksForAllLocations(ref ReadableBuffer readBuffer, byte emptyValue)
        {
            byte huntValue = (byte)~emptyValue;

            // we're going to fully index the final locations of the buffer, so that we
            // can mutate etc in constant time
            var addresses = BuildPointerIndex(ref readBuffer);

            // check it isn't there to start with
            ReadableBuffer slice;
            ReadCursor     cursor;
            var            found = readBuffer.TrySliceTo(huntValue, out slice, out cursor);

            Assert.False(found);

            // correctness test all values
            for (int i = 0; i < readBuffer.Length; i++)
            {
                *addresses[i] = huntValue;
                found = readBuffer.TrySliceTo(huntValue, out slice, out cursor);
                *addresses[i] = emptyValue;

                Assert.True(found);
                var   remaining = readBuffer.Slice(cursor);
                void *pointer;
                Assert.True(remaining.First.TryGetPointer(out pointer));
                Assert.True((byte *)pointer == addresses[i]);
            }
        }
Example #18
0
        // TODO: not sure how to do this; basically I want to lease a writable, expandable area
        // for a duration, and be able to access it for reading, and release
        internal void AddBacklog(ref ReadableBuffer buffer, ref WebSocketsFrame frame)
        {
            var length = frame.PayloadLength;

            if (length == 0)
            {
                return;              // nothing to store!
            }
            var slicedBuffer = buffer.Slice(0, length);

            // unscramble the data
            if (frame.Mask != 0)
            {
                WebSocketsFrame.ApplyMask(ref slicedBuffer, frame.Mask);
            }

            var backlog = this.backlog;

            if (backlog == null)
            {
                var newBacklog = new List <ReadableBuffer>();
                backlog = Interlocked.CompareExchange(ref this.backlog, newBacklog, null) ?? newBacklog;
            }
            backlog.Add(slicedBuffer.Preserve());
        }
Example #19
0
        /// <summary>
        /// Trim whitespace starting from the specified <see cref="ReadableBuffer"/>.
        /// </summary>
        /// <param name="buffer">The <see cref="ReadableBuffer"/> to trim</param>
        /// <returns>A new <see cref="ReadableBuffer"/> with the starting whitespace trimmed.</returns>
        public static ReadableBuffer TrimEnd(this ReadableBuffer buffer)
        {
            var end = -1;
            var i   = 0;

            foreach (var memory in buffer)
            {
                var span = memory.Span;
                for (int j = 0; j < span.Length; j++)
                {
                    i++;
                    if (IsWhitespaceChar(span[j]))
                    {
                        if (end == -1)
                        {
                            end = i;
                        }
                    }
                    else
                    {
                        end = -1;
                    }
                }
            }

            return(end != -1 ? buffer.Slice(0, end - 1) : buffer);
        }
Example #20
0
 public static bool TryParse(ReadableBuffer payload, out WebSocketCloseResult result, out ushort?actualCloseCode)
 {
     if (payload.Length == 0)
     {
         // Empty payload is OK
         actualCloseCode = null;
         result          = new WebSocketCloseResult(WebSocketCloseStatus.Empty, string.Empty);
         return(true);
     }
     else if (payload.Length < 2)
     {
         actualCloseCode = null;
         result          = default(WebSocketCloseResult);
         return(false);
     }
     else
     {
         var status = payload.ReadBigEndian <ushort>();
         actualCloseCode = status;
         var description = string.Empty;
         payload = payload.Slice(2);
         if (payload.Length > 0)
         {
             description = payload.GetUtf8String();
         }
         result = new WebSocketCloseResult((WebSocketCloseStatus)status, description);
         return(true);
     }
 }
Example #21
0
        public static int ReadBigEndian24bit(this ReadableBuffer buffer)
        {
            uint contentSize = buffer.ReadBigEndian <ushort>();

            contentSize = (contentSize << 8) + buffer.Slice(2).ReadBigEndian <byte>();
            return((int)contentSize);
        }
Example #22
0
        // the `unsafe` here is so that in the "multiple spans, header crosses spans", we can use stackalloc to
        // collate the header bytes in one place, and pass that down for analysis
        internal unsafe static bool TryReadFrameHeader(ref ReadableBuffer buffer, out WebSocketsFrame frame)
        {
            int bytesAvailable = buffer.Length;

            if (bytesAvailable < 2)
            {
                frame = default(WebSocketsFrame);
                return(false); // can't read that; frame takes at minimum two bytes
            }

            var firstSpan = buffer.First;

            if (buffer.IsSingleSpan || firstSpan.Length >= MaxHeaderLength)
            {
                return(TryReadFrameHeader(firstSpan.Length, firstSpan.Span, ref buffer, out frame));
            }
            else
            {
                // header is at most 14 bytes; can afford the stack for that - but note that if we aim for 16 bytes instead,
                // we will usually benefit from using 2 qword copies
                byte *header     = stackalloc byte[16];
                var   slice      = buffer.Slice(0, Math.Min(16, bytesAvailable));
                var   headerSpan = new Span <byte>(header, slice.Length);
                slice.CopyTo(headerSpan);

                // note that we're using the "slice" above to preview the header, but we
                // still want to pass the *original* buffer down below, so that we can
                // check the overall length (payload etc)
                return(TryReadFrameHeader(slice.Length, headerSpan, ref buffer, out frame));
            }
        }
Example #23
0
            private void ParseChunkedTrailer(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
            {
                consumed = buffer.Start;
                examined = buffer.Start;

                if (buffer.Length < 2)
                {
                    examined = buffer.End;
                    return;
                }

                var trailerBuffer = buffer.Slice(0, 2);
                var trailerSpan   = trailerBuffer.ToSpan();

                if (trailerSpan[0] == '\r' && trailerSpan[1] == '\n')
                {
                    consumed = trailerBuffer.End;
                    examined = trailerBuffer.End;
                    AddAndCheckConsumedBytes(2);
                    _mode = Mode.Complete;
                }
                else
                {
                    _mode = Mode.TrailerHeaders;
                }
            }
Example #24
0
            private void ParseChunkedSuffix(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
            {
                consumed = buffer.Start;
                examined = buffer.Start;

                if (buffer.Length < 2)
                {
                    examined = buffer.End;
                    return;
                }

                var suffixBuffer = buffer.Slice(0, 2);
                var suffixSpan   = suffixBuffer.ToSpan();

                if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n')
                {
                    consumed = suffixBuffer.End;
                    examined = suffixBuffer.End;
                    AddAndCheckConsumedBytes(2);
                    _mode = Mode.Prefix;
                }
                else
                {
                    _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSuffix);
                }
            }
Example #25
0
        public static void ReadCertificates(ReadableBuffer buffer, SecurePipelineListener listener)
        {
            buffer = buffer.Slice(HandshakeProcessor.HandshakeHeaderSize);
            //ignore context
            BufferExtensions.SliceVector <byte>(ref buffer);
            //slice the list
            buffer = BufferExtensions.SliceVector24Bit(ref buffer);
            X509Certificate2Collection collection;

            if (listener.CertificateValidation == null)
            {
                collection = null;
            }
            else
            {
                collection = new X509Certificate2Collection();
            }
            while (buffer.Length > 0)
            {
                var cert = BufferExtensions.SliceVector24Bit(ref buffer);
                var ext  = BufferExtensions.SliceVector <ushort>(ref buffer);
                if (cert.Length > 0 && collection != null)
                {
                    var x509 = new X509Certificate2(cert.ToArray());
                    collection.Add(x509);
                }
            }
            if (collection != null)
            {
                if (!listener.CertificateValidation(collection))
                {
                    Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.bad_certificate, "Failed to verify the certificate chain via the callback");
                }
            }
        }
 private static ReadCursor ProcessHeader(HttpContext context, ref ReadableBuffer currentSlice)
 {
     if (!currentSlice.TrySliceTo(HttpConsts.EndOfLine, out ReadableBuffer headerLine, out ReadCursor cursor))
     {
         headerLine   = currentSlice;
         currentSlice = currentSlice.Slice(currentSlice.Length);
     }
        internal unsafe static bool TryReadFrameHeader(ref ReadableBuffer buffer, out WebSocketsFrame frame)
        {
            int bytesAvailable = buffer.Length;

            if (bytesAvailable < 2)
            {
                frame = default(WebSocketsFrame);
                return(false); // can't read that; frame takes at minimum two bytes
            }

            var span = buffer.FirstSpan;

            if (buffer.IsSingleSpan || span.Length >= MaxHeaderLength)
            {
                return(TryReadFrameHeader(span.Length, (byte *)span.BufferPtr, ref buffer, out frame));
            }
            else
            {
                // header is at most 14 bytes; can afford the stack for that - but note that if we aim for 16 bytes instead,
                // we will usually benefit from using 2 qword copies (handled internally); very very small messages ('a') might
                // have to use the slower version, but... meh
                byte *header = stackalloc byte[16];
                var   slice  = buffer.Slice(0, Math.Min(16, bytesAvailable));
                slice.CopyTo(header, slice.Length);
                // note that we're using the "slice" above to preview the header, but we
                // still want to pass the original buffer down below, so that we can
                // check the overall length (payload etc)
                return(TryReadFrameHeader(slice.Length, header, ref buffer, out frame));
            }
        }
Example #28
0
        private unsafe void TestIndexOfWorksForAllLocations(ref ReadableBuffer readBuffer, byte emptyValue)
        {
            byte          huntValue  = (byte)~emptyValue;
            Vector <byte> huntVector = new Vector <byte>(huntValue);

            // we're going to fully index the final locations of the buffer, so that we
            // can mutate etc in constant time
            var addresses = BuildPointerIndex(ref readBuffer);

            // check it isn't there to start with
            var found = readBuffer.IndexOf(ref huntVector);

            Assert.True(found == ReadCursor.NotFound);

            // correctness test all values
            for (int i = 0; i < readBuffer.Length; i++)
            {
                *addresses[i] = huntValue;
                found = readBuffer.IndexOf(ref huntVector);
                *addresses[i] = emptyValue;

                Assert.True(found != ReadCursor.NotFound);
                var slice = readBuffer.Slice(found);
                Assert.True(slice.FirstSpan.UnsafePointer == addresses[i]);
            }
        }
Example #29
0
        public bool TakeMessageHeaders(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
        {
            // Make sure the buffer is limited
            bool overLength = false;

            if (buffer.Length >= _remainingRequestHeadersBytesAllowed)
            {
                buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed);

                // If we sliced it means the current buffer bigger than what we're
                // allowed to look at
                overLength = true;
            }

            var result = _parser.ParseHeaders(new Http1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes);

            _remainingRequestHeadersBytesAllowed -= consumedBytes;

            if (!result && overLength)
            {
                ThrowRequestRejected(RequestRejectionReason.HeadersExceedMaxTotalSize);
            }
            if (result)
            {
                TimeoutControl.CancelTimeout();
            }

            return(result);
        }
Example #30
0
        public void RegisterSessionTicket(ReadableBuffer buffer)
        {
            //slice off the head first
            buffer = buffer.Slice(HandshakeProcessor.HandshakeHeaderSize);
            uint ticketAge, ageRandom;

            buffer = buffer.SliceBigEndian(out ticketAge);
            buffer = buffer.SliceBigEndian(out ageRandom);
            var ticketData = BufferExtensions.SliceVector <ushort>(ref buffer);

            if (buffer.Length > 0)
            {
                //Extensions
                buffer = BufferExtensions.SliceVector <ushort>(ref buffer);
                if (buffer.Length > 0)
                {
                    //seems we can resume data
                    ExtensionType type;
                    buffer = buffer.SliceBigEndian(out type);
                    if (type != ExtensionType.ticket_early_data_info)
                    {
                        Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "Early session ticket received had an invalid extension");
                    }
                }
            }
        }
        private unsafe void TestIndexOfWorksForAllLocations(ref ReadableBuffer readBuffer, byte emptyValue)
        {
            byte huntValue = (byte)~emptyValue;

            // we're going to fully index the final locations of the buffer, so that we
            // can mutate etc in constant time
            var addresses = BuildPointerIndex(ref readBuffer);

            // check it isn't there to start with
            ReadableBuffer slice;
            ReadCursor cursor;
            var found = readBuffer.TrySliceTo(huntValue, out slice, out cursor);
            Assert.False(found);

            // correctness test all values 
            for (int i = 0; i < readBuffer.Length; i++)
            {
                *addresses[i] = huntValue;
                found = readBuffer.TrySliceTo(huntValue, out slice, out cursor);
                *addresses[i] = emptyValue;

                Assert.True(found);
                var remaining = readBuffer.Slice(cursor);
                void* pointer;
                Assert.True(remaining.First.TryGetPointer(out pointer));
                Assert.True((byte*)pointer == addresses[i]);
            }
        }
        public ParseResult ParseRequest(ref ReadableBuffer buffer)
        {
            if (_state == ParsingState.StartLine)
            {
                // Find \n
                ReadCursor delim;
                ReadableBuffer startLine;
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out startLine, out delim))
                {
                    return ParseResult.Incomplete;
                }

                // Move the buffer to the rest
                buffer = buffer.Slice(delim).Slice(2);

                ReadableBuffer method;
                if (!startLine.TrySliceTo((byte)' ', out method, out delim))
                {
                    return ParseResult.BadRequest;
                }

                _method = method.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                ReadableBuffer path;
                if (!startLine.TrySliceTo((byte)' ', out path, out delim))
                {
                    return ParseResult.BadRequest;
                }

                _path = path.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                var httpVersion = startLine;
                if (httpVersion.IsEmpty)
                {
                    return ParseResult.BadRequest;
                }

                _httpVersion = httpVersion.Preserve();

                _state = ParsingState.Headers;
            }

            // Parse headers
            // key: value\r\n

            while (!buffer.IsEmpty)
            {
                var headerName = default(ReadableBuffer);
                var headerValue = default(ReadableBuffer);

                // End of the header
                // \n
                ReadCursor delim;
                ReadableBuffer headerPair;
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out headerPair, out delim))
                {
                    return ParseResult.Incomplete;
                }

                buffer = buffer.Slice(delim).Slice(2);

                // End of headers
                if (headerPair.IsEmpty)
                {
                    return ParseResult.Complete;
                }

                // :
                if (!headerPair.TrySliceTo((byte)':', out headerName, out delim))
                {
                    return ParseResult.BadRequest;
                }

                headerName = headerName.TrimStart();
                headerPair = headerPair.Slice(delim).Slice(1);

                headerValue = headerPair.TrimStart();
                RequestHeaders.SetHeader(ref headerName, ref headerValue);
            }

            return ParseResult.Incomplete;
        }
 private unsafe void TestValue(ref ReadableBuffer readBuffer, ulong value)
 {
     void* pointer;
     Assert.True(readBuffer.First.TryGetPointer(out pointer));
     var ptr = (byte*)pointer;
     string s = value.ToString(CultureInfo.InvariantCulture);
     int written;
     fixed (char* c = s)
     {
         written = Encoding.ASCII.GetBytes(c, s.Length, ptr, readBuffer.Length);
     }
     var slice = readBuffer.Slice(0, written);
     Assert.Equal(value, slice.GetUInt64());
 }