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; }
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); }
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; }
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); }
/// <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()); }
/// <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(); }
/// <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); }
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; }
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); }
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(); } } }
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)); }
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}"); } }
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); }
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); }
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}"); }
public override void SetClientRandom(ReadableBuffer readableBuffer) { readableBuffer.CopyTo(_schedule.ClientRandom); }