Beispiel #1
0
        public unsafe void SetPeerKey(ReadableBuffer buffer)
        {
            if (buffer.Length != _keyExchangeSize)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, $"The peer key is not the length of the keyexchange size {buffer.Length} - {_keyExchangeSize}");
            }
            GCHandle handle;
            void *   ptr;

            if (buffer.IsSingleSpan)
            {
                ptr = buffer.First.GetPointer(out handle);
            }
            else
            {
                var tmpBuffer = stackalloc byte[buffer.Length];
                var span      = new Span <byte>(tmpBuffer, buffer.Length);
                buffer.CopyTo(span);
                ptr = tmpBuffer;
            }
            _peerKey = EVP_PKEY_new();
            ThrowOnError(EVP_PKEY_set_type(_peerKey, _nid));
            ThrowOnError(EVP_PKEY_set1_tls_encodedpoint(_peerKey, ptr, (UIntPtr)buffer.Length));

            if (!_publicPrivateKey.IsValid())
            {
                GenerateKeyset();
            }
            _hasPeerKey = true;
        }
Beispiel #2
0
        public unsafe static ulong GetUInt64(this ReadableBuffer buffer)
        {
            byte *addr;
            ulong value;
            int   consumed, len = buffer.Length;

            if (buffer.IsSingleSpan)
            {
                // It fits!
                addr = (byte *)buffer.FirstSpan.UnsafePointer;
            }
            else if (len < 128) // REVIEW: What's a good number
            {
                var data = stackalloc byte[len];
                buffer.CopyTo(new Span <byte>(data, len));
                addr = data; // memory allocated via stackalloc is valid and
                // intact until the end of the method; we don't need to worry about scope
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                var arr = buffer.ToArray();
                if (!InvariantParser.TryParse(arr, 0, FormattingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
                {
                    throw new InvalidOperationException();
                }
                return(value);
            }

            if (!InvariantParser.TryParse(addr, 0, len, FormattingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
            {
                throw new InvalidOperationException();
            }
            return(value);
        }
Beispiel #3
0
        public unsafe void SetPeerKey(ReadableBuffer peerKey)
        {
            if (peerKey.Length != _keyExchangeSize)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, $"The client key didn't match the expected length");
            }
            int cbKey;

            peerKey = peerKey.Slice(1);
            cbKey   = peerKey.Length / 2;
            GenerateKeys();
            int keyLength = peerKey.Length;
            //Now we have the point and can load the key
            var keyBuffer  = stackalloc byte[keyLength + 8];
            var blobHeader = new BCRYPT_ECCKEY_BLOB();

            blobHeader.Magic = KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC;
            blobHeader.cbKey = cbKey;
            Marshal.StructureToPtr(blobHeader, (IntPtr)keyBuffer, false);
            peerKey.CopyTo(new Span <byte>(keyBuffer + 8, keyLength));
            SafeBCryptKeyHandle keyHandle;

            ExceptionHelper.CheckReturnCode(BCryptImportKeyPair(_algo, IntPtr.Zero, KeyBlobType.BCRYPT_ECCPUBLIC_BLOB, out keyHandle, (IntPtr)keyBuffer, keyLength + 8, 0));
            _peerKey    = keyHandle;
            _hasPeerKey = true;
        }
Beispiel #4
0
        public unsafe KeySchedule(IConnectionStateTls13 state, EphemeralBufferPoolWindows pool, ReadableBuffer resumptionSecret)
        {
            _pool      = pool;
            _stateData = pool.Rent();
            _state     = state;
            _hashSize  = CryptoProvider.HashProvider.HashSize(CipherSuite.HashType);

            _stateData.Memory.TryGetPointer(out _secret);
            _clientHandshakeTrafficSecret = ((byte *)_secret) + _hashSize;
            _serverHandshakeTrafficSecret = _clientHandshakeTrafficSecret + _hashSize;
            _masterSecret = _serverHandshakeTrafficSecret + _hashSize;
            _clientApplicationTrafficSecret = _masterSecret + _hashSize;
            _serverApplicationTrafficSecret = _clientApplicationTrafficSecret + _hashSize;

            void *resumptionPointer = null;
            int   secretLength      = 0;

            if (resumptionSecret.Length > 0)
            {
                var stackSecret = stackalloc byte[resumptionSecret.Length];
                resumptionSecret.CopyTo(new Span <byte>(stackSecret, resumptionSecret.Length));
                secretLength      = resumptionSecret.Length;
                resumptionPointer = stackSecret;
            }
            HkdfFunctions.HkdfExtract(CryptoProvider.HashProvider, CipherSuite.HashType, null, 0, resumptionPointer, secretLength, _secret, _hashSize);
        }
Beispiel #5
0
        /// <summary>
        /// Decodes the utf8 encoded bytes in the <see cref="ReadableBuffer"/> into a <see cref="string"/>
        /// </summary>
        /// <param name="buffer">The buffer to decode</param>
        public static unsafe string GetUtf8String(this ReadableBuffer buffer)
        {
            if (buffer.IsEmpty)
            {
                return(null);
            }

            ReadOnlySpan <byte> textSpan;

            if (buffer.IsSingleSpan)
            {
                textSpan = buffer.First.Span;
            }
            else if (buffer.Length < 128) // REVIEW: What's a good number
            {
                var data        = stackalloc byte[128];
                var destination = new Span <byte>(data, 128);

                buffer.CopyTo(destination);

                textSpan = destination.Slice(0, buffer.Length);
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                textSpan = new ReadOnlySpan <byte>(buffer.ToArray());
            }

            return(new Utf8String(textSpan).ToString());
        }
Beispiel #6
0
        /// <summary>
        /// Parses a <see cref="ulong"/> from the specified <see cref="ReadableBuffer"/>
        /// </summary>
        /// <param name="buffer">The <see cref="ReadableBuffer"/> to parse</param>
        public static ulong GetUInt64(this ReadableBuffer buffer)
        {
            ulong value;

            if (Utf8Parser.TryParseUInt64(buffer.First.Span, out value))
            {
                return(value);
            }

            if (buffer.IsSingleSpan) // no more data to parse
            {
                throw new InvalidOperationException();
            }

            var bufferLength = buffer.Length;

            int toParseLength = 21; // longest invariant UTF8 UInt64 + 1 (so we know there is a delimiter at teh end)

            if (bufferLength < 21)
            {
                toParseLength = (int)bufferLength;
            }

            Span <byte> toParseBuffer = stackalloc byte[toParseLength];

            buffer.CopyTo(toParseBuffer);

            if (Utf8Parser.TryParseUInt64(toParseBuffer, out value))
            {
                return(value);
            }

            throw new InvalidOperationException();
        }
Beispiel #7
0
        /// <summary>
        /// Decodes the utf8 encoded bytes in the <see cref="ReadableBuffer"/> into a <see cref="string"/>
        /// </summary>
        /// <param name="buffer">The buffer to decode</param>
        public static string GetUtf8String(this ReadableBuffer buffer)
        {
            if (buffer.IsEmpty)
            {
                return(null);
            }

            // Assign 'textSpan' to something formally stack-referring.
            // The default classification is "returnable, not referring to stack", we want the opposite in this case.
            ReadOnlySpan <byte> textSpan = stackalloc byte[0];

            if (buffer.IsSingleSpan)
            {
                textSpan = buffer.First.Span;
            }
            else if (buffer.Length < 128) // REVIEW: What's a good number
            {
                Span <byte> destination = stackalloc byte[128];
                buffer.CopyTo(destination);

                // We are able to cast because buffer.Length < 128
                textSpan = destination.Slice(0, (int)buffer.Length);
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                textSpan = new ReadOnlySpan <byte>(buffer.ToArray());
            }

            return(new Utf8String(textSpan).ToString());
        }
        public unsafe static uint GetUInt32(this ReadableBuffer buffer)
        {
            var textSpan = default(ReadOnlySpan <byte>);

            if (buffer.IsSingleSpan)
            {
                // It fits!
                var span = buffer.FirstSpan;
                textSpan = new ReadOnlySpan <byte>(span.Array, span.Offset, span.Length);
            }
            else if (buffer.Length < 128) // REVIEW: What's a good number
            {
                var target = stackalloc byte[128];

                buffer.CopyTo(target, length: 128);

                textSpan = new ReadOnlySpan <byte>(target, buffer.Length);
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                textSpan = new ReadOnlySpan <byte>(buffer.ToArray());
            }

            uint value;
            var  utf8Buffer = new Utf8String(textSpan);

            if (!InvariantParser.TryParse(utf8Buffer, out value))
            {
                throw new InvalidOperationException();
            }
            return(value);
        }
Beispiel #9
0
        public unsafe void SetPeerKey(ReadableBuffer peerKey)
        {
            GenerateKeys(null, null);
            if (peerKey.Length != _keyExchangeSize)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.illegal_parameter, "The client key didn't match the expected size");
            }
            GCHandle handle = default(GCHandle);

            try
            {
                void *ptr;
                if (peerKey.IsSingleSpan)
                {
                    ptr = peerKey.First.GetPointer(out handle);
                }
                else
                {
                    var sBuffer = stackalloc byte[peerKey.Length];
                    peerKey.CopyTo(new Span <byte>(sBuffer, peerKey.Length));
                    ptr = sBuffer;
                }
                _clientBN = BN_bin2bn(ptr, peerKey.Length, IntPtr.Zero);
            }
            finally
            {
                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }
            _hasPeerKey = true;
        }
Beispiel #10
0
        public unsafe static uint GetUInt32(this ReadableBuffer buffer)
        {
            ReadOnlySpan <byte> textSpan;

            if (buffer.IsSingleSpan)
            {
                // It fits!
                textSpan = buffer.FirstSpan;
            }
            else if (buffer.Length < 128) // REVIEW: What's a good number
            {
                var data        = stackalloc byte[128];
                var destination = new Span <byte>(data, 128);

                buffer.CopyTo(destination);

                textSpan = destination.Slice(0, buffer.Length);
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                textSpan = new ReadOnlySpan <byte>(buffer.ToArray());
            }

            uint value;
            var  utf8Buffer = new Utf8String(textSpan);

            if (!InvariantParser.TryParse(utf8Buffer, out value))
            {
                throw new InvalidOperationException();
            }
            return(value);
        }
Beispiel #11
0
        internal unsafe static void ReadClientFinished(ReadableBuffer messageBuffer, ServerStateTls13Draft18 state)
        {
            messageBuffer = messageBuffer.Slice(4);
            var hashSize = state.HandshakeHash.HashSize;

            //We could let the equals function worry about this
            //however to avoid allocations we will copy a fragmented
            //client hash into the stack as it is small
            //however an attacker could send a large messge
            //and cause a stack overflow
            if (messageBuffer.Length != hashSize)
            {
                Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, "Client finished is the wrong size (not equal to hash size)");
            }
            //We have the client hash so we need to grab the client base key
            //and the hash up until now and make sure that the data is good
            var hash = stackalloc byte[hashSize];

            state.HandshakeHash.InterimHash(hash, hashSize);

            var key = state.KeySchedule.GenerateClientFinishedKey();

            fixed(byte *kPtr = key)
            {
                state.CryptoProvider.HashProvider.HmacData(state.CipherSuite.HashType, kPtr, key.Length, hash, hashSize, hash, hashSize);
            }

            Span <byte> clientHash;
            GCHandle    handle = default(GCHandle);

            if (messageBuffer.IsSingleSpan)
            {
                var ptr = messageBuffer.First.GetPointer(out handle);
                clientHash = new Span <byte>(ptr, hashSize);
            }
            else
            {
                var bptr = stackalloc byte[hashSize];
                clientHash = new Span <byte>(bptr, hashSize);
                messageBuffer.CopyTo(clientHash);
            }
            try
            {
                if (!Internal.CompareFunctions.ConstantTimeEquals(clientHash, new Span <byte>(hash, hashSize)))
                {
                    Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.bad_record_mac, "The mac of the client finished did not match the expected");
                }
            }
            finally
            {
                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }
        }
        /// <summary>
        /// Parses a <see cref="ulong"/> from the specified <see cref="ReadableBuffer"/>
        /// </summary>
        /// <param name="buffer">The <see cref="ReadableBuffer"/> to parse</param>
        public unsafe static ulong GetUInt64(this ReadableBuffer buffer)
        {
            byte *addr;
            ulong value;
            int   consumed, len = buffer.Length;

            if (buffer.IsSingleSpan)
            {
                // It fits!
                void *pointer;
                ArraySegment <byte> data;
                if (buffer.First.TryGetPointer(out pointer))
                {
                    if (!PrimitiveParser.TryParseUInt64((byte *)pointer, 0, len, EncodingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
                    {
                        throw new InvalidOperationException();
                    }
                }
                else if (buffer.First.TryGetArray(out data))
                {
                    if (!PrimitiveParser.TryParseUInt64(data.Array, 0, EncodingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
                    {
                        throw new InvalidOperationException();
                    }
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
            else if (len < 128) // REVIEW: What's a good number
            {
                var data = stackalloc byte[len];
                buffer.CopyTo(new Span <byte>(data, len));
                addr = data;

                if (!PrimitiveParser.TryParseUInt64(addr, 0, len, EncodingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                var arr = buffer.ToArray();
                if (!PrimitiveParser.TryParseUInt64(arr, 0, EncodingData.InvariantUtf8, Format.Parsed.HexUppercase, out value, out consumed))
                {
                    throw new InvalidOperationException();
                }

                return(value);
            }

            return(value);
        }
        internal static string ComputeReply(ReadableBuffer key, BufferSpan buffer)
        {
            //To prove that the handshake was received, the server has to take two
            //pieces of information and combine them to form a response.  The first
            //piece of information comes from the |Sec-WebSocket-Key| header field
            //in the client handshake:

            //     Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

            //For this header field, the server has to take the value (as present
            //in the header field, e.g., the base64-encoded [RFC4648] version minus
            //any leading and trailing whitespace) and concatenate this with the
            //Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-
            //95CA-C5AB0DC85B11" in string form, which is unlikely to be used by
            //network endpoints that do not understand the WebSocket Protocol.  A
            //SHA-1 hash (160 bits) [FIPS.180-3], base64-encoded (see Section 4 of
            //[RFC4648]), of this concatenation is then returned in the server's
            //handshake.

            const int ExpectedKeyLength = 24;

            key = ReadableBufferExtensions.TrimStart(key);
            int len = key.Length, baseOffset = buffer.Offset;

            if (len != ExpectedKeyLength)
            {
                throw new ArgumentException("Invalid key length", nameof(key));
            }

            if (buffer.Length < (ExpectedKeyLength + WebSocketKeySuffixBytes.Length))
            {
                throw new ArgumentException("Insufficient buffer space", nameof(buffer));
            }

            // use the output buffer as a scratch pad to compute the hash
            byte[] arr = buffer.Array;
            key.CopyTo(arr, baseOffset);
            Buffer.BlockCopy( // append the magic number from RFC6455
                WebSocketKeySuffixBytes, 0,
                arr, baseOffset + ExpectedKeyLength,
                WebSocketKeySuffixBytes.Length);

            // compute the hash
            using (var sha = SHA1.Create())
            {
                var hash = sha.ComputeHash(arr, baseOffset,
                                           ExpectedKeyLength + WebSocketKeySuffixBytes.Length);
                return(Convert.ToBase64String(hash));
            }
        }
        private static unsafe void ParseJson(ReadableBuffer buffer)
        {
            Utf8String json;

            if (buffer.IsSingleSpan)
            {
                json = new Utf8String(buffer.First.Span);
            }
            else
            {
                var   length = buffer.Length;
                byte *b      = stackalloc byte[length];
                buffer.CopyTo(new Span <byte>(b, length));
                json = new Utf8String(new ReadOnlySpan <byte>(b, length));
            }
            //Console.WriteLine(utf8Str.Length);

            var reader = new JsonReader(json);

            while (reader.Read())
            {
                var tokenType = reader.TokenType;
                switch (tokenType)
                {
                case JsonReader.JsonTokenType.ObjectStart:
                case JsonReader.JsonTokenType.ObjectEnd:
                case JsonReader.JsonTokenType.ArrayStart:
                case JsonReader.JsonTokenType.ArrayEnd:
                    //Console.WriteLine(tokenType);
                    break;

                case JsonReader.JsonTokenType.Property:
                    var name = reader.GetName();
                    //Console.WriteLine(name);
                    var value = reader.GetValue();
                    //Console.WriteLine(value);
                    break;

                case JsonReader.JsonTokenType.Value:
                    value = reader.GetValue();
                    //Console.WriteLine(value);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
        }
Beispiel #15
0
        internal unsafe static int ComputeReply(ReadableBuffer key, Span <byte> destination)
        {
            if (key.IsSingleSpan)
            {
                return(ComputeReply(key.First.Span, destination));
            }
            if (key.Length != SecRequestLength)
            {
                throw new ArgumentException("Invalid key length", nameof(key));
            }
            byte *ptr  = stackalloc byte[SecRequestLength];
            var   span = new Span <byte>(ptr, SecRequestLength);

            key.CopyTo(span);
            return(ComputeReply(destination, destination));
        }
Beispiel #16
0
        public unsafe static bool ConstantTimeEquals(Span <byte> a, ReadableBuffer b)
        {
            Span <byte> bSpan;

            if (b.IsSingleSpan)
            {
                bSpan = b.First.Span;
            }
            else
            {
                var tempBuffer = stackalloc byte[b.Length];
                bSpan = new Span <byte>(tempBuffer, b.Length);
                b.CopyTo(bSpan);
            }
            return(ConstantTimeEquals(a, bSpan));
        }
        internal static unsafe void Encrypt <T>(this T context, WritableBuffer outBuffer, ReadableBuffer buffer) where T : ISecureContext
        {
            outBuffer.Ensure(context.TrailerSize + context.HeaderSize + buffer.Length);
            void *outBufferPointer;

            outBuffer.Memory.TryGetPointer(out outBufferPointer);

            buffer.CopyTo(outBuffer.Memory.Slice(context.HeaderSize, buffer.Length));

            var securityBuff = stackalloc SecurityBuffer[4];
            SecurityBufferDescriptor sdcInOut = new SecurityBufferDescriptor(4);

            securityBuff[0].size         = context.HeaderSize;
            securityBuff[0].type         = SecurityBufferType.Header;
            securityBuff[0].tokenPointer = outBufferPointer;

            securityBuff[1].size         = buffer.Length;
            securityBuff[1].type         = SecurityBufferType.Data;
            securityBuff[1].tokenPointer = (byte *)outBufferPointer + context.HeaderSize;

            securityBuff[2].size         = context.TrailerSize;
            securityBuff[2].type         = SecurityBufferType.Trailer;
            securityBuff[2].tokenPointer = (byte *)outBufferPointer + context.HeaderSize + buffer.Length;

            securityBuff[3].size         = 0;
            securityBuff[3].tokenPointer = null;
            securityBuff[3].type         = SecurityBufferType.Empty;

            sdcInOut.UnmanagedPointer = securityBuff;

            var handle = context.ContextHandle;
            var result = (SecurityStatus)InteropSspi.EncryptMessage(ref handle, 0, sdcInOut, 0);

            if (result == 0)
            {
                outBuffer.Advance(context.HeaderSize + context.TrailerSize + buffer.Length);
            }
            else
            {
                //Zero out the output buffer before throwing the exception to stop any data being sent in the clear
                //By a misbehaving underlying channel
                Span <byte> memoryToClear = new Span <byte>(outBufferPointer, context.HeaderSize + context.TrailerSize + buffer.Length);
                byte *      empty         = stackalloc byte[context.HeaderSize + context.TrailerSize + buffer.Length];
                memoryToClear.Set(empty, context.HeaderSize + context.TrailerSize + buffer.Length);
                throw new InvalidOperationException($"There was an issue encrypting the data {result}");
            }
        }
Beispiel #18
0
        public unsafe void SetPeerKey(ReadableBuffer peerKey)
        {
            GenerateECKeySet();

            var group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(_eKey));
            var point = EC_POINT_new(group);

            try
            {
                var handle = default(GCHandle);
                try
                {
                    void *ptr;
                    if (peerKey.IsSingleSpan)
                    {
                        ptr = peerKey.First.GetPointer(out handle);
                    }
                    else
                    {
                        var tmpBuffer = stackalloc byte[peerKey.Length];
                        var span      = new Span <byte>(tmpBuffer, peerKey.Length);
                        peerKey.CopyTo(span);
                        ptr = tmpBuffer;
                    }
                    ThrowOnError(EC_POINT_oct2point(group, point, ptr, (IntPtr)peerKey.Length, null));
                }
                finally
                {
                    if (handle.IsAllocated)
                    {
                        handle.Free();
                    }
                }
                var ecClientKey = EC_KEY_new_by_curve_name(_curveNid);
                ThrowOnError(EC_KEY_set_public_key(ecClientKey, point));
                _clientKey = EVP_PKEY_new();
                ThrowOnError(EVP_PKEY_assign_EC_KEY(_clientKey, ecClientKey));
                _hasPeerKey = true;
            }
            finally
            {
                point.Free();
            }
        }
        /// <summary>
        /// Parses a <see cref="ulong"/> from the specified <see cref="ReadableBuffer"/>
        /// </summary>
        /// <param name="buffer">The <see cref="ReadableBuffer"/> to parse</param>
        public unsafe static ulong GetUInt64(this ReadableBuffer buffer)
        {
            byte *addr;
            ulong value;
            var   len = buffer.Length;

            if (buffer.IsSingleSpan)
            {
                // It fits!
                fixed(byte *source = &buffer.First.Span.DangerousGetPinnableReference())
                {
                    // We are able to cast because IsSingleSpan and span size is int
                    if (!PrimitiveParser.InvariantUtf8.TryParseUInt64(source, (int)len, out value))
                    {
                        ThrowInvalidOperation();
                    }
                }
            }
            else if (len < 128) // REVIEW: What's a good number
            {
                // We are able to cast because len < 128
                var length = (int)len;
                var data   = stackalloc byte[length];
                buffer.CopyTo(new Span <byte>(data, length));
                addr = data;
                if (!PrimitiveParser.InvariantUtf8.TryParseUInt64(addr, length, out value))
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                // Heap allocated copy to parse into array (should be rare)
                var arr = buffer.ToArray();
                if (!PrimitiveParser.InvariantUtf8.TryParseUInt64(arr, out value))
                {
                    throw new InvalidOperationException();
                }

                return(value);
            }

            return(value);
        }
Beispiel #20
0
        private async Task Send(HttpContext context, ReadableBuffer data)
        {
            // TODO: Pooled buffers
            // 8 = 6(data: ) + 2 (\n\n)
            var buffer = new byte[8 + data.Length];
            var at     = 0;

            buffer[at++] = (byte)'d';
            buffer[at++] = (byte)'a';
            buffer[at++] = (byte)'t';
            buffer[at++] = (byte)'a';
            buffer[at++] = (byte)':';
            buffer[at++] = (byte)' ';
            data.CopyTo(new Span <byte>(buffer, at, data.Length));
            at          += data.Length;
            buffer[at++] = (byte)'\n';
            buffer[at++] = (byte)'\n';
            await context.Response.Body.WriteAsync(buffer, 0, at);

            await context.Response.Body.FlushAsync();
        }
        internal static unsafe SecurityStatus Decrypt <T>(this T context, ReadableBuffer buffer, WritableBuffer decryptedData) where T : ISecureContext
        {
            void *pointer;

            if (buffer.IsSingleSpan)
            {
                buffer.First.TryGetPointer(out pointer);
            }
            else
            {
                if (buffer.Length > SecurityContext.MaxStackAllocSize)
                {
                    throw new OverflowException($"We need to create a buffer on the stack of size {buffer.Length} but the max is {SecurityContext.MaxStackAllocSize}");
                }
                byte *      tmpBuffer = stackalloc byte[buffer.Length];
                Span <byte> span      = new Span <byte>(tmpBuffer, buffer.Length);
                buffer.CopyTo(span);
                pointer = tmpBuffer;
            }

            int offset = 0;
            int count  = buffer.Length;

            var secStatus = DecryptMessage(pointer, ref offset, ref count, context.ContextHandle);

            if (buffer.IsSingleSpan)
            {
                buffer = buffer.Slice(offset, count);
                decryptedData.Append(ref buffer);
            }
            else
            {
                decryptedData.Ensure(buffer.Length);
                decryptedData.Write(new Span <byte>(pointer, buffer.Length));
            }
            return(secStatus);
        }
Beispiel #22
0
        public byte[] ProcessContextMessage(ReadableBuffer messageBuffer)
        {
            GCHandle handleForAllocation = default(GCHandle);

            try
            {
                SecurityBufferDescriptor output     = new SecurityBufferDescriptor(2);
                SecurityBuffer *         outputBuff = stackalloc SecurityBuffer[2];
                outputBuff[0].size         = 0;
                outputBuff[0].tokenPointer = null;
                outputBuff[0].type         = SecurityBufferType.Token;
                outputBuff[1].type         = SecurityBufferType.Alert;
                outputBuff[1].size         = 0;
                outputBuff[1].tokenPointer = null;

                output.UnmanagedPointer = outputBuff;

                var        handle      = _securityContext.CredentialsHandle;
                SSPIHandle localhandle = _contextPointer;
                void *     contextptr;
                void *     newContextptr;
                if (_contextPointer.handleHi == IntPtr.Zero && _contextPointer.handleLo == IntPtr.Zero)
                {
                    contextptr    = null;
                    newContextptr = &localhandle;
                }
                else
                {
                    contextptr    = &localhandle;
                    newContextptr = null;
                }

                ContextFlags unusedAttributes = default(ContextFlags);
                SecurityBufferDescriptor *pointerToDescriptor = null;

                if (messageBuffer.Length > 0)
                {
                    SecurityBufferDescriptor input     = new SecurityBufferDescriptor(2);
                    SecurityBuffer *         inputBuff = stackalloc SecurityBuffer[2];
                    inputBuff[0].size = messageBuffer.Length;
                    inputBuff[0].type = SecurityBufferType.Token;

                    if (messageBuffer.IsSingleSpan)
                    {
                        void *arrayPointer;
                        messageBuffer.First.TryGetPointer(out arrayPointer);
                        inputBuff[0].tokenPointer = arrayPointer;
                    }
                    else
                    {
                        if (messageBuffer.Length <= SecurityContext.MaxStackAllocSize)
                        {
                            byte *      tempBuffer = stackalloc byte[messageBuffer.Length];
                            Span <byte> tmpSpan    = new Span <byte>(tempBuffer, messageBuffer.Length);
                            messageBuffer.CopyTo(tmpSpan);
                            inputBuff[0].tokenPointer = tempBuffer;
                        }
                        else
                        {
                            //We have to allocate... sorry
                            byte[]      tempBuffer = new byte[messageBuffer.Length];
                            Span <byte> tmpSpan    = new Span <byte>(tempBuffer);
                            messageBuffer.CopyTo(tmpSpan);
                            handleForAllocation       = GCHandle.Alloc(tempBuffer, GCHandleType.Pinned);
                            inputBuff[0].tokenPointer = (void *)handleForAllocation.AddrOfPinnedObject();
                        }
                    }

                    outputBuff[1].type         = SecurityBufferType.Empty;
                    outputBuff[1].size         = 0;
                    outputBuff[1].tokenPointer = null;

                    input.UnmanagedPointer = inputBuff;
                    pointerToDescriptor    = &input;
                }
                else
                {
                    if (_securityContext.LengthOfSupportedProtocols > 0)
                    {
                        SecurityBufferDescriptor input     = new SecurityBufferDescriptor(1);
                        SecurityBuffer *         inputBuff = stackalloc SecurityBuffer[1];
                        inputBuff[0].size = _securityContext.LengthOfSupportedProtocols;

                        inputBuff[0].tokenPointer = (void *)_securityContext.AlpnSupportedProtocols;

                        inputBuff[0].type = SecurityBufferType.ApplicationProtocols;

                        input.UnmanagedPointer = inputBuff;
                        pointerToDescriptor    = &input;
                    }
                }

                long           timestamp = 0;
                SecurityStatus errorCode = (SecurityStatus)InteropSspi.InitializeSecurityContextW(ref handle, contextptr, _securityContext.HostName, SecurityContext.RequiredFlags | ContextFlags.InitManualCredValidation, 0, Endianness.Native, pointerToDescriptor, 0, newContextptr, output, ref unusedAttributes, out timestamp);

                _contextPointer = localhandle;

                if (errorCode == SecurityStatus.ContinueNeeded || errorCode == SecurityStatus.OK)
                {
                    byte[] outArray = null;
                    if (outputBuff[0].size > 0)
                    {
                        outArray = new byte[outputBuff[0].size];
                        Marshal.Copy((IntPtr)outputBuff[0].tokenPointer, outArray, 0, outputBuff[0].size);
                        InteropSspi.FreeContextBuffer((IntPtr)outputBuff[0].tokenPointer);
                    }
                    if (errorCode == SecurityStatus.OK)
                    {
                        ContextStreamSizes ss;
                        //We have a valid context so lets query it for info
                        InteropSspi.QueryContextAttributesW(ref _contextPointer, ContextAttribute.StreamSizes, out ss);
                        _headerSize  = ss.header;
                        _trailerSize = ss.trailer;

                        if (_securityContext.LengthOfSupportedProtocols > 0)
                        {
                            _negotiatedProtocol = ApplicationProtocols.FindNegotiatedProtocol(_contextPointer);
                        }
                        _readyToSend = true;
                    }
                    return(outArray);
                }

                throw new InvalidOperationException($"An error occured trying to negoiate a session {errorCode}");
            }
            finally
            {
                if (handleForAllocation.IsAllocated)
                {
                    handleForAllocation.Free();
                }
            }
        }
        public byte[] ProcessContextMessage(ReadableBuffer messageBuffer)
        {
            if (messageBuffer.Length == 0)
            {
                return(null);
            }
            SecurityBufferDescriptor input     = new SecurityBufferDescriptor(3);
            SecurityBuffer *         inputBuff = stackalloc SecurityBuffer[3];

            void *arrayPointer;

            if (messageBuffer.IsSingleSpan)
            {
                messageBuffer.First.TryGetPointer(out arrayPointer);
            }
            else
            {
                if (messageBuffer.Length > SecurityContext.MaxStackAllocSize)
                {
                    throw new OverflowException($"We need to create a buffer on the stack of size {messageBuffer.Length} but the max is {SecurityContext.MaxStackAllocSize}");
                }
                byte *tempBytes = stackalloc byte[messageBuffer.Length];
                messageBuffer.CopyTo(new Span <byte>(tempBytes, messageBuffer.Length));
                arrayPointer = tempBytes;
            }

            inputBuff[0] = new SecurityBuffer()
            {
                tokenPointer = arrayPointer,
                type         = SecurityBufferType.Token,
                size         = messageBuffer.Length
            };

            inputBuff[1] = new SecurityBuffer()
            {
                size         = 0,
                tokenPointer = null,
                type         = SecurityBufferType.Empty
            };

            if (_securityContext.LengthOfSupportedProtocols > 0)
            {
                inputBuff[2].size         = _securityContext.LengthOfSupportedProtocols;
                inputBuff[2].tokenPointer = (void *)_securityContext.AlpnSupportedProtocols;
                inputBuff[2].type         = SecurityBufferType.ApplicationProtocols;
            }
            else
            {
                inputBuff[2].size         = 0;
                inputBuff[2].tokenPointer = null;
                inputBuff[2].type         = SecurityBufferType.Empty;
            }
            input.UnmanagedPointer = inputBuff;

            SecurityBufferDescriptor output     = new SecurityBufferDescriptor(3);
            SecurityBuffer *         outputBuff = stackalloc SecurityBuffer[3];

            outputBuff[0].size         = 0;
            outputBuff[0].tokenPointer = null;
            outputBuff[0].type         = SecurityBufferType.Token;
            outputBuff[1].size         = 0;
            outputBuff[1].tokenPointer = null;
            outputBuff[1].type         = SecurityBufferType.Alert;
            outputBuff[2].size         = 0;
            outputBuff[2].tokenPointer = null;
            outputBuff[2].type         = SecurityBufferType.Empty;
            output.UnmanagedPointer    = outputBuff;

            ContextFlags flags = default(ContextFlags);
            long         timestamp;
            var          handle = _securityContext.CredentialsHandle;
            void *       contextptr;
            var          localPointer = _contextPointer;

            if (_contextPointer.handleHi == IntPtr.Zero && _contextPointer.handleLo == IntPtr.Zero)
            {
                contextptr = null;
            }
            else
            {
                contextptr = &localPointer;
            }
            var errorCode = (SecurityStatus)InteropSspi.AcceptSecurityContext(ref handle, contextptr, input, SecurityContext.ServerRequiredFlags, Endianness.Native, ref _contextPointer, output, ref flags, out timestamp);

            _contextPointer = localPointer;

            if (errorCode == SecurityStatus.ContinueNeeded || errorCode == SecurityStatus.OK)
            {
                byte[] outArray = null;
                if (outputBuff[0].size > 0)
                {
                    outArray = new byte[outputBuff[0].size];
                    Marshal.Copy((IntPtr)outputBuff[0].tokenPointer, outArray, 0, outputBuff[0].size);
                    InteropSspi.FreeContextBuffer((IntPtr)outputBuff[0].tokenPointer);
                }
                if (errorCode == SecurityStatus.OK)
                {
                    ContextStreamSizes ss;
                    //We have a valid context so lets query it for info
                    InteropSspi.QueryContextAttributesW(ref _contextPointer, ContextAttribute.StreamSizes, out ss);
                    _headerSize  = ss.header;
                    _trailerSize = ss.trailer;

                    if (_securityContext.LengthOfSupportedProtocols > 0)
                    {
                        _negotiatedProtocol = ApplicationProtocols.FindNegotiatedProtocol(_contextPointer);
                    }
                    _readyToSend = true;
                }
                return(outArray);
            }
            throw new InvalidOperationException($"We failed to build a server context {errorCode}");
        }
Beispiel #24
0
 public override void SetClientRandom(ReadableBuffer readableBuffer)
 {
     readableBuffer.CopyTo(_schedule.ClientRandom);
 }