кто-нибудь знает, как я могу реализовать TLS-ALPN в .NET?
Я реализовал базовый сервер HTTP/2, но без шифрования TLS. Я искал в google, но нашел ресурсы только для C, Java или других языков, но ничего для .NET (C#)
кто-нибудь знает, как я могу реализовать TLS-ALPN в .NET?
Я реализовал базовый сервер HTTP/2, но без шифрования TLS. Я искал в google, но нашел ресурсы только для C, Java или других языков, но ничего для .NET (C#)
Согласно проекту HttpTwo на Github, в настоящее время это невозможно из-за ошибки.
Обновление: не поддерживается в .NET. Вы можете проголосовать за него здесь: https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/6264363-add-support-for-alpn-to-system-net-security-sslstr
цитировать:
HTTP/2 RFC утверждает, что безопасные соединения должны использовать ALPN для согласования протокола. К сожалению, SslStream .NET не имеет возможности указывать протоколы приложений как часть аутентификации TLS, поэтому он не может поддерживать ALPN. Существует ошибка, отслеживающая эту проблему на dotnetfix, однако похоже, что это не произойдет очень скоро (особенно на моно и .NET 4.x).
На самом деле это возможно. Немного поразмыслив, вы можете внедрить любое расширение в приветствие клиента или сервера.
Вот некоторый код, чтобы дать вам представление:
// Refer IANA on ApplicationProtocols: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
public static void FixALPN(params string[] protocols) {
if (Interlocked.Increment(ref cntFixALPN) > 1)
{
throw new Exception("FixALPN should be called only ONCE, put it in your Main or use a static constructor.");
return;
}
// get the needed (internal) System types
string tpname = typeof(System.Net.HttpListener).AssemblyQualifiedName;
Type tpiface = Type.GetType(tpname.Replace("HttpListener", "SSPIInterface"));
Type tpgsspi = Type.GetType(tpname.Replace("HttpListener", "GlobalSSPI"));
Type tpsdc = Type.GetType(tpname.Replace("HttpListener", "SafeDeleteContext"));
Type tpsecbuf = Type.GetType(tpname.Replace("HttpListener", "SecurityBuffer"));
// create ALPN buffer
ConstructorInfo ci = (from x in tpsecbuf.GetConstructors() where x.GetParameters().Length == 4 select x).First();
var secbufempty = ci.Invoke(new object[] { new byte[0], 0, 0, 0 });
byte[] btsalpn = GetALPNBuffer(protocols);
var secbufalpn = ci.Invoke(new object[] { btsalpn, 0, btsalpn.Length, 18 });
// grab the object to replace...
FieldInfo fi = tpgsspi.GetField("SSPISecureChannel", BindingFlags.NonPublic | BindingFlags.Static);
var secchan = fi.GetValue(null);
// ...and the method(s) we'll use in our intercepted call(s)
MethodInfo miSDC_ISC = tpsdc.GetMethod("InitializeSecurityContext", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo miSDC_ASC = tpsdc.GetMethod("AcceptSecurityContext", BindingFlags.NonPublic | BindingFlags.Static);
// fake the internal interface
var result = new InterfaceImplementer(tpiface, (mcm) => {
MethodInfo mi = (MethodInfo)mcm.MethodBase;
object[] args = mcm.Args;
object ret = null;
if (mi.Name == "InitializeSecurityContext") // For Client Mode
{
if (args[5] == null) // empty input, new connection
{
dynamic[] secbufs = (dynamic[])Activator.CreateInstance(miSDC_ASC.GetParameters()[6].ParameterType, new object[] { 1 });
secbufs[0] = secbufalpn;
object[] sdcargs = new object[] { 0, args[0], args[1], args[2], args[3], args[4],
null,
secbufs,
args[6], args[7]
};
ret = miSDC_ISC.Invoke(null, sdcargs);
args[0] = sdcargs[1];
args[1] = sdcargs[2];
args[7] = sdcargs[9];
}
else
{
ret = mi.Invoke(secchan, args);
}
}
else if (mi.Name == "AcceptSecurityContext") // For Server Mode
{
dynamic[] secbufs = (dynamic[])Activator.CreateInstance(miSDC_ASC.GetParameters()[6].ParameterType, new object[] { 3 });
secbufs[0] = args[2];
secbufs[1] = secbufempty;
secbufs[2] = secbufalpn;
object[] sdcargs = new object[] { 0, args[0], args[1], args[3], args[4],
null,
secbufs,
args[5], args[6]
};
ret = miSDC_ASC.Invoke(null, sdcargs);
args[0] = sdcargs[1];
args[1] = sdcargs[2];
args[6] = sdcargs[8];
}
else
ret = mi.Invoke(secchan, args);
return new ReturnMessage(ret, args, args.Length, mcm.LogicalCallContext, mcm);
}).GetTransparentProxy();
// and set it, done
fi.SetValue(null, result);
}
.NET Core 2.1.2 включает необходимые изменения в SslStream, необходимые для поддержки ALPN. Это еще не задокументировано, но запрос на включение, который добавляет его, находится здесь