Commit b3e44a6c authored by Honfika's avatar Honfika

Add ALPN Ssl extension

parent 6178e0c9
......@@ -5,25 +5,26 @@ namespace Titanium.Web.Proxy.Helpers
class CustomBufferedPeekStream
{
private readonly CustomBufferedStream baseStream;
private int position;
public int Position { get; private set; }
public CustomBufferedPeekStream(CustomBufferedStream baseStream, int startPosition = 0)
{
this.baseStream = baseStream;
position = startPosition;
Position = startPosition;
}
public int Available => baseStream.Available - position;
public int Available => baseStream.Available - Position;
public async Task<bool> EnsureBufferLength(int length)
{
var val = await baseStream.PeekByteAsync(position + length - 1);
var val = await baseStream.PeekByteAsync(Position + length - 1);
return val != -1;
}
public byte ReadByte()
{
return baseStream.PeekByteFromBuffer(position++);
return baseStream.PeekByteFromBuffer(Position++);
}
public int ReadInt16()
......
using System.Diagnostics;
using System.IO;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Ssl;
namespace Titanium.Web.Proxy.Network.Tcp
{
internal class ClientHelloAlpnAdderStream : Stream
{
private CustomBufferedStream stream;
public ClientHelloAlpnAdderStream(CustomBufferedStream stream)
{
this.stream = stream;
}
public override void Flush()
{
stream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
[DebuggerStepThrough]
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
var ms = new MemoryStream(buffer, offset, count);
//this can be non async, because reads from a memory stream
var clientHello = SslTools.GetClientHelloInfo(new CustomBufferedStream(ms, (int)ms.Length)).Result;
if (clientHello != null)
{
// 0x00 0x10: ALPN identifier
// 0x00 0x0e: length of ALPN data
// 0x00 0x0c: length of ALPN data again:)
var dataToAdd = new byte[] { 0x0, 0x10, 0x0, 0xE, 0x0, 0xC,
2, (byte)'h', (byte)'2',
8, (byte)'h', (byte)'t', (byte)'t', (byte)'p', (byte)'/', (byte)'1', (byte)'.', (byte)'1' };
int newByteCount = clientHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length;
var buffer2 = new byte[buffer.Length + newByteCount];
for (int i = 0; i < buffer.Length; i++)
{
buffer2[i] = buffer[i];
}
//this is a hacky solution, but works
int length = (buffer[offset + 3] << 8) + buffer[offset + 4];
length += newByteCount;
buffer2[offset + 3] = (byte)(length >> 8);
buffer2[offset + 4] = (byte)length;
length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8];
length += newByteCount;
buffer2[offset + 6] = (byte)(length >> 16);
buffer2[offset + 7] = (byte)(length >> 8);
buffer2[offset + 8] = (byte)length;
if (clientHello.Extensions != null)
{
// update ALPN length
int pos = offset + clientHello.EntensionsStartPosition;
length = (buffer[pos] << 8) + buffer[pos + 1];
length += newByteCount;
buffer2[pos] = (byte)(length >> 8);
buffer2[pos + 1] = (byte)length;
}
else
{
// add ALPN length
buffer2[buffer.Length] = 0;
buffer2[buffer.Length + 1] = 18;
}
for (int i = 0; i < dataToAdd.Length; i++)
{
buffer2[buffer2.Length - dataToAdd.Length + i] = dataToAdd[i];
}
// copy the reamining data if any
for (int i = clientHello.ClientHelloLength; i < count; i++)
{
buffer2[offset + newByteCount + i] = buffer[offset + clientHello.ClientHelloLength];
}
buffer = buffer2;
count += newByteCount;
}
stream.Write(buffer, offset, count);
}
public override bool CanRead => stream.CanRead;
public override bool CanSeek => stream.CanSeek;
public override bool CanWrite => stream.CanWrite;
public override long Length => stream.Length;
public override long Position
{
get { return stream.Position; }
set { stream.Position = value; }
}
}
}
\ No newline at end of file
using System;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
......@@ -104,7 +105,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
if (isHttps)
{
var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
bool alpnEnabled = false;
var alpnStream = alpnEnabled ? (Stream)new ClientHelloAlpnAdderStream(stream) : stream;
var sslStream = new SslStream(alpnStream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, server.BufferSize);
await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation);
......
......@@ -39,6 +39,10 @@ namespace Titanium.Web.Proxy.Ssl
public byte[] CompressionData { get; set; }
internal int ClientHelloLength { get; set; }
internal int EntensionsStartPosition { get; set; }
public List<SslExtension> Extensions { get; set; }
private static string SslVersionToString(int major, int minor)
......
......@@ -109,8 +109,12 @@ namespace Titanium.Web.Proxy.Ssl
byte[] compressionData = peekStream.ReadBytes(length);
int extenstionsStartPosition = peekStream.Position;
var extensions = await ReadExtensions(majorVersion, minorVersion, peekStream);
//var rawBytes = new CustomBufferedPeekStream(clientStream).ReadBytes(peekStream.Position);
var clientHelloInfo = new ClientHelloInfo
{
MajorVersion = majorVersion,
......@@ -119,6 +123,8 @@ namespace Titanium.Web.Proxy.Ssl
SessionId = sessionId,
Ciphers = ciphers,
CompressionData = compressionData,
ClientHelloLength = peekStream.Position,
EntensionsStartPosition = extenstionsStartPosition,
Extensions = extensions,
};
......
......@@ -98,6 +98,7 @@
<Compile Include="Helpers\HttpHelper.cs" />
<Compile Include="Helpers\Network.cs" />
<Compile Include="Helpers\Tcp.cs" />
<Compile Include="Network\Tcp\ClientHelloAlpnAdderStream.cs" />
<Compile Include="Ssl\ServerHelloInfo.cs" />
<Compile Include="Ssl\ClientHelloInfo.cs" />
<Compile Include="Http\ConnectRequest.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment