未验证 提交 f8d5706a 编写于 作者: T Tomas Weinfurt 提交者: GitHub

PoC TLS resume on Linux client (#64369)

* TLS resume on client

* shim functions introduced in 1.1.1

* add missing struct

* disable resume on old OpenSSL

* feedback from review

* fix source build

* update comment

* feedback from review

* feedback from review

* avoild client resume on old OpenSSL
上级 286492c9
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
......@@ -21,7 +22,9 @@ internal static partial class OpenSsl
{
private const string DisableTlsResumeCtxSwitch = "System.Net.Security.DisableTlsResume";
private const string DisableTlsResumeEnvironmentVariable = "DOTNET_SYSTEM_NET_SECURITY_DISABLETLSRESUME";
private const SslProtocols FakeAlpnSslProtocol = (SslProtocols)1; // used to distinguish server sessions with ALPN
private static readonly IdnMapping s_idnMapping = new IdnMapping();
private static readonly ConcurrentDictionary<SslProtocols, SafeSslContextHandle> s_clientSslContexts = new ConcurrentDictionary<SslProtocols, SafeSslContextHandle>();
#region internal methods
internal static SafeChannelBindingHandle? QueryChannelBinding(SafeSslHandle context, ChannelBindingKind bindingType)
......@@ -80,7 +83,7 @@ private static bool DisableTlsResume
private static SslProtocols CalculateEffectiveProtocols(SslAuthenticationOptions sslAuthenticationOptions)
{
// make sure low bit is not set since we use it in context dictionary to distinguish use with ALPN
Debug.Assert(((int)sslAuthenticationOptions.EnabledSslProtocols & 1) == 0);
Debug.Assert((sslAuthenticationOptions.EnabledSslProtocols & FakeAlpnSslProtocol) == 0);
SslProtocols protocols = sslAuthenticationOptions.EnabledSslProtocols & ~((SslProtocols)1);
if (!Interop.Ssl.Capabilities.Tls13Supported)
......@@ -127,7 +130,7 @@ private static SslProtocols CalculateEffectiveProtocols(SslAuthenticationOptions
}
// This essentially wraps SSL_CTX* aka SSL_CTX_new + setting
internal static SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols, bool enableResume)
internal static unsafe SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols, bool enableResume)
{
SafeX509Handle? certHandle = credential.CertHandle;
SafeEvpPKeyHandle? certKeyHandle = credential.CertKeyHandle;
......@@ -164,16 +167,13 @@ internal static SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials c
Debug.Assert(cipherSuites == null || (cipherSuites.Length >= 1 && cipherSuites[cipherSuites.Length - 1] == 0));
unsafe
fixed (byte* cipherListStr = cipherList)
fixed (byte* cipherSuitesStr = cipherSuites)
{
fixed (byte* cipherListStr = cipherList)
fixed (byte* cipherSuitesStr = cipherSuites)
if (!Ssl.SslCtxSetCiphers(sslCtx, cipherListStr, cipherSuitesStr))
{
if (!Ssl.SslCtxSetCiphers(sslCtx, cipherListStr, cipherSuitesStr))
{
Crypto.ErrClearError();
throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy));
}
Crypto.ErrClearError();
throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy));
}
}
......@@ -186,15 +186,28 @@ internal static SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials c
// https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html
Ssl.SslCtxSetQuietShutdown(sslCtx);
Ssl.SslCtxSetCaching(sslCtx, enableResume ? 1 : 0);
if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0)
if (enableResume)
{
unsafe
if (sslAuthenticationOptions.IsServer)
{
Ssl.SslCtxSetCaching(sslCtx, 1, null, null);
}
else
{
Interop.Ssl.SslCtxSetAlpnSelectCb(sslCtx, &AlpnServerSelectCallback, IntPtr.Zero);
int result = Ssl.SslCtxSetCaching(sslCtx, 1, &NewSessionCallback, &RemoveSessionCallback);
Debug.Assert(result == 1);
sslCtx.EnableSessionCache();
}
}
else
{
Ssl.SslCtxSetCaching(sslCtx, 0, null, null);
}
if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0)
{
Interop.Ssl.SslCtxSetAlpnSelectCb(sslCtx, &AlpnServerSelectCallback, IntPtr.Zero);
}
bool hasCertificateAndKey =
certHandle != null && !certHandle.IsInvalid
......@@ -269,15 +282,47 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia
SafeSslContextHandle? newCtxHandle = null;
SslProtocols protocols = CalculateEffectiveProtocols(sslAuthenticationOptions);
bool hasAlpn = sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0;
bool cacheSslContext = !DisableTlsResume && sslAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.RequireEncryption &&
sslAuthenticationOptions.IsServer &&
sslAuthenticationOptions.CertificateContext != null &&
sslAuthenticationOptions.CertificateContext.SslContexts != null &&
sslAuthenticationOptions.CipherSuitesPolicy == null;
bool cacheSslContext = !DisableTlsResume && sslAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.RequireEncryption && sslAuthenticationOptions.CipherSuitesPolicy == null;
if (cacheSslContext)
{
sslAuthenticationOptions.CertificateContext!.SslContexts!.TryGetValue(protocols | (SslProtocols)(hasAlpn ? 1 : 0), out sslCtxHandle);
if (sslAuthenticationOptions.IsClient)
{
// We don't support client resume on old OpenSSL versions.
// We don't want to try on empty TargetName since that is our key.
// And we don't want to mess up with client authentication. It may be possible
// but it seems safe to get full new session.
if (!Interop.Ssl.Capabilities.Tls13Supported ||
string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) ||
sslAuthenticationOptions.CertificateContext != null ||
sslAuthenticationOptions.CertSelectionDelegate != null)
{
cacheSslContext = false;
}
}
else
{
// Server should always have certificate
Debug.Assert(sslAuthenticationOptions.CertificateContext != null);
if (sslAuthenticationOptions.CertificateContext == null ||
sslAuthenticationOptions.CertificateContext.SslContexts == null)
{
cacheSslContext = false;
}
}
}
if (cacheSslContext)
{
if (sslAuthenticationOptions.IsServer)
{
sslAuthenticationOptions.CertificateContext!.SslContexts!.TryGetValue(protocols | (hasAlpn ? FakeAlpnSslProtocol : SslProtocols.None), out sslCtxHandle);
}
else
{
s_clientSslContexts.TryGetValue(protocols, out sslCtxHandle);
}
}
if (sslCtxHandle == null)
......@@ -285,9 +330,15 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia
// We did not get SslContext from cache
sslCtxHandle = newCtxHandle = AllocateSslContext(credential, sslAuthenticationOptions, protocols, cacheSslContext);
if (cacheSslContext && sslAuthenticationOptions.CertificateContext!.SslContexts!.TryAdd(protocols | (SslProtocols)(hasAlpn ? 1 : 0), newCtxHandle))
if (cacheSslContext)
{
newCtxHandle = null;
bool added = sslAuthenticationOptions.IsServer ?
sslAuthenticationOptions.CertificateContext!.SslContexts!.TryAdd(protocols | (SslProtocols)(hasAlpn ? 1 : 0), newCtxHandle) :
s_clientSslContexts.TryAdd(protocols, newCtxHandle);
if (added)
{
newCtxHandle = null;
}
}
}
......@@ -306,6 +357,7 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia
{
if (sslAuthenticationOptions.IsServer)
{
Debug.Assert(Interop.Ssl.SslGetData(sslHandle) == IntPtr.Zero);
alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols);
Interop.Ssl.SslSetData(sslHandle, GCHandle.ToIntPtr(alpnHandle));
sslHandle.AlpnHandle = alpnHandle;
......@@ -319,7 +371,7 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia
}
}
if (!sslAuthenticationOptions.IsServer)
if (sslAuthenticationOptions.IsClient)
{
// The IdnMapping converts unicode input into the IDNA punycode sequence.
string punyCode = string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) ? string.Empty : s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost!);
......@@ -330,6 +382,11 @@ internal static SafeSslHandle AllocateSslHandle(SafeFreeSslCredentials credentia
Crypto.ErrClearError();
}
if (cacheSslContext && !string.IsNullOrEmpty(punyCode))
{
sslCtxHandle.TrySetSession(sslHandle, punyCode);
}
// relevant to TLS 1.3 only: if user supplied a client cert or cert callback,
// advertise that we are willing to send the certificate post-handshake.
if (sslAuthenticationOptions.ClientCertificates?.Count > 0 ||
......@@ -644,6 +701,58 @@ private static unsafe int AlpnServerSelectCallback(IntPtr ssl, byte** outp, byte
return Ssl.SSL_TLSEXT_ERR_ALERT_FATAL;
}
[UnmanagedCallersOnly]
// Invoked from OpenSSL when new session is created.
// We attached GCHandle to the SSL so we can find back SafeSslContextHandle holding the cache.
// New session has refCount of 1.
// If this function returns 0, OpenSSL will drop the refCount and discard the session.
// If we return 1, the ownership is transfered to us and we will need to call SessionFree().
private static unsafe int NewSessionCallback(IntPtr ssl, IntPtr session)
{
Debug.Assert(ssl != IntPtr.Zero);
Debug.Assert(session != IntPtr.Zero);
IntPtr ptr = Ssl.SslGetData(ssl);
Debug.Assert(ptr != IntPtr.Zero);
GCHandle gch = GCHandle.FromIntPtr(ptr);
SafeSslContextHandle? ctxHandle = gch.Target as SafeSslContextHandle;
// There is no relation between SafeSslContextHandle and SafeSslHandle so the handle
// may be released while the ssl session is still active.
if (ctxHandle != null && ctxHandle.TryAddSession(Ssl.SslGetServerName(ssl), session))
{
// offered session was stored in our cache.
return 1;
}
// OpenSSL will destroy session.
return 0;
}
[UnmanagedCallersOnly]
private static unsafe void RemoveSessionCallback(IntPtr ctx, IntPtr session)
{
Debug.Assert(ctx != IntPtr.Zero && session != IntPtr.Zero);
IntPtr ptr = Ssl.SslCtxGetData(ctx);
if (ptr == IntPtr.Zero)
{
// Same as above, SafeSslContextHandle could be released while OpenSSL still holds reference.
return;
}
GCHandle gch = GCHandle.FromIntPtr(ptr);
SafeSslContextHandle? ctxHandle = gch.Target as SafeSslContextHandle;
if (ctxHandle == null)
{
return;
}
IntPtr name = Ssl.SessionGetHostname(session);
Debug.Assert(name != IntPtr.Zero);
ctxHandle.RemoveSession(name, session);
}
private static int BioRead(SafeBioHandle bio, byte[] buffer, int count)
{
Debug.Assert(buffer != null);
......
......@@ -57,6 +57,12 @@ internal static partial class Ssl
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool SslSetTlsExtHostName(SafeSslHandle ssl, string host);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetServerName")]
internal static unsafe partial IntPtr SslGetServerName(IntPtr ssl);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetSession")]
internal static unsafe partial int SslSetSession(SafeSslHandle ssl, IntPtr session);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGet0AlpnSelected")]
internal static partial void SslGetAlpnSelected(SafeSslHandle ssl, out IntPtr protocol, out int len);
......@@ -146,6 +152,9 @@ internal static partial class Ssl
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetData")]
internal static partial IntPtr SslGetData(IntPtr ssl);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetData")]
internal static partial IntPtr SslGetData(SafeSslHandle ssl);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetData")]
internal static partial int SslSetData(SafeSslHandle ssl, IntPtr data);
......@@ -167,6 +176,15 @@ internal static partial class Ssl
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Tls13Supported")]
private static partial int Tls13SupportedImpl();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSessionGetHostname")]
internal static partial IntPtr SessionGetHostname(IntPtr session);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSessionFree")]
internal static partial void SessionFree(IntPtr session);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSessionSetHostname")]
internal static partial int SessionSetHostname(IntPtr session, IntPtr name);
internal static class Capabilities
{
// needs separate type (separate static cctor) to be sure OpenSSL is initialized.
......
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
......@@ -19,11 +20,20 @@ internal static partial class Ssl
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxDestroy")]
internal static partial void SslCtxDestroy(IntPtr ctx);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxGetData")]
internal static partial IntPtr SslCtxGetData(IntPtr ctx);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetData")]
internal static partial int SslCtxSetData(SafeSslContextHandle ctx, IntPtr data);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetData")]
internal static partial int SslCtxSetData(IntPtr ctx, IntPtr data);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnSelectCb")]
internal static unsafe partial void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, delegate* unmanaged<IntPtr, byte**, byte*, byte*, uint, IntPtr, int> callback, IntPtr arg);
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetCaching")]
internal static unsafe partial void SslCtxSetCaching(SafeSslContextHandle ctx, int mode);
internal static unsafe partial int SslCtxSetCaching(SafeSslContextHandle ctx, int mode, delegate* unmanaged<IntPtr, IntPtr, int> neewSessionCallback, delegate* unmanaged<IntPtr, IntPtr, void> removeSessionCallback);
internal static bool AddExtraChainCertificates(SafeSslContextHandle ctx, X509Certificate2[] chain)
{
......@@ -50,6 +60,10 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeSslContextHandle : SafeHandle
{
// This is session cache keyed by SNI e.g. TargetHost
private Dictionary<string, IntPtr>? _sslSessions;
private GCHandle _gch;
public SafeSslContextHandle()
: base(IntPtr.Zero, true)
{
......@@ -67,9 +81,136 @@ public override bool IsInvalid
protected override bool ReleaseHandle()
{
if (_sslSessions != null)
{
// The SSL_CTX is ref counted and may not immediately die when we call SslCtxDestroy()
// Since there is no relation between SafeSslContextHandle and SafeSslHandle `this` can be release
// while we still have SSL session using it.
Interop.Ssl.SslCtxSetData(handle, IntPtr.Zero);
lock (_sslSessions)
{
foreach (IntPtr session in _sslSessions.Values)
{
Interop.Ssl.SessionFree(session);
}
_sslSessions.Clear();
}
Debug.Assert(_gch.IsAllocated);
_gch.Free();
}
Interop.Ssl.SslCtxDestroy(handle);
SetHandle(IntPtr.Zero);
return true;
}
internal void EnableSessionCache()
{
Debug.Assert(_sslSessions == null);
_sslSessions = new Dictionary<string, IntPtr>();
_gch = GCHandle.Alloc(this);
Debug.Assert(_gch.IsAllocated);
// This is needed so we can find the handle from session in SessionRemove callback.
Interop.Ssl.SslCtxSetData(this, (IntPtr)_gch);
}
internal bool TryAddSession(IntPtr namePtr, IntPtr session)
{
Debug.Assert(_sslSessions != null && session != IntPtr.Zero);
if (_sslSessions == null || namePtr == IntPtr.Zero)
{
return false;
}
string? targetName = Marshal.PtrToStringAnsi(namePtr);
Debug.Assert(targetName != null);
if (!string.IsNullOrEmpty(targetName))
{
// We do this only for lookup in RemoveSession.
// Since this is part of chache manipulation and no function impact it is done here.
// This will use strdup() so it is safe to pass in raw pointer.
Interop.Ssl.SessionSetHostname(session, namePtr);
lock (_sslSessions)
{
if (!_sslSessions.TryAdd(targetName, session))
{
if (_sslSessions.Remove(targetName, out IntPtr oldSession))
{
Interop.Ssl.SessionFree(oldSession);
}
bool added = _sslSessions.TryAdd(targetName, session);
Debug.Assert(added);
}
}
return true;
}
return false;
}
internal void RemoveSession(IntPtr namePtr, IntPtr session)
{
Debug.Assert(_sslSessions != null);
string? targetName = Marshal.PtrToStringAnsi(namePtr);
Debug.Assert(targetName != null);
if (_sslSessions != null && targetName != null)
{
IntPtr oldSession;
bool removed;
lock (_sslSessions)
{
removed = _sslSessions.Remove(targetName, out oldSession);
}
if (removed)
{
// It seems like we may be called more than once. Since we grabbed only one refference
// when added to Dictionary, we will also drop exactly one when removed.
Interop.Ssl.SessionFree(oldSession);
}
}
}
internal bool TrySetSession(SafeSslHandle sslHandle, string name)
{
Debug.Assert(_sslSessions != null);
if (_sslSessions == null || string.IsNullOrEmpty(name))
{
return false;
}
// even if we don't have matching session, we can get new one and we need
// way how to link SSL back to `this`.
Debug.Assert(Interop.Ssl.SslGetData(sslHandle) == IntPtr.Zero);
Interop.Ssl.SslSetData(sslHandle, (IntPtr)_gch);
lock (_sslSessions)
{
if (_sslSessions.TryGetValue(name, out IntPtr session))
{
// This will increase reference count on the session as needed.
// We need to hold lock here to prevent session being deleted before the call is done.
Interop.Ssl.SslSetSession(sslHandle, session);
return true;
}
}
return false;
}
}
}
......@@ -311,6 +311,8 @@
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Crypto.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSsl.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSsl.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.Ssl.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Ssl.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.SslCtx.cs"
......
......@@ -142,6 +142,7 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto
internal X509CertificateCollection? ClientCertificates { get; set; }
internal List<SslApplicationProtocol>? ApplicationProtocols { get; set; }
internal bool IsServer { get; set; }
internal bool IsClient => !IsServer;
internal SslStreamCertificateContext? CertificateContext { get; set; }
internal SslProtocols EnabledSslProtocols { get; set; }
internal X509RevocationMode CertificateRevocationCheckMode { get; set; }
......
......@@ -889,5 +889,4 @@ int local_EVP_PKEY_public_check(EVP_PKEY_CTX* ctx)
return -1;
}
}
#endif
......@@ -293,7 +293,9 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_SslCtxCheckPrivateKey)
DllImportEntry(CryptoNative_SslCtxCreate)
DllImportEntry(CryptoNative_SslCtxDestroy)
DllImportEntry(CryptoNative_SslCtxGetData)
DllImportEntry(CryptoNative_SslCtxSetAlpnSelectCb)
DllImportEntry(CryptoNative_SslCtxSetData)
DllImportEntry(CryptoNative_SslCtxSetProtocolOptions)
DllImportEntry(CryptoNative_SslCtxSetQuietShutdown)
DllImportEntry(CryptoNative_SslCtxUseCertificate)
......@@ -310,8 +312,12 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_SslGetPeerCertChain)
DllImportEntry(CryptoNative_SslGetPeerCertificate)
DllImportEntry(CryptoNative_SslGetPeerFinished)
DllImportEntry(CryptoNative_SslGetServerName)
DllImportEntry(CryptoNative_SslGetVersion)
DllImportEntry(CryptoNative_SslRead)
DllImportEntry(CryptoNative_SslSessionFree)
DllImportEntry(CryptoNative_SslSessionGetHostname)
DllImportEntry(CryptoNative_SslSessionSetHostname)
DllImportEntry(CryptoNative_SslSessionReused)
DllImportEntry(CryptoNative_SslSetAcceptState)
DllImportEntry(CryptoNative_SslSetAlpnProtos)
......@@ -321,6 +327,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_SslSetConnectState)
DllImportEntry(CryptoNative_SslSetData)
DllImportEntry(CryptoNative_SslSetQuietShutdown)
DllImportEntry(CryptoNative_SslSetSession)
DllImportEntry(CryptoNative_SslSetTlsExtHostName)
DllImportEntry(CryptoNative_SslSetVerifyPeer)
DllImportEntry(CryptoNative_SslShutdown)
......
......@@ -169,7 +169,8 @@ struct x509_store_st
X509_VERIFY_PARAM* param;
};
struct bio_st {
struct bio_st
{
const void* _ignored1;
const void* _ignored2;
const void* _ignored3;
......
......@@ -467,13 +467,17 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
FALLBACK_FUNCTION(SSL_CTX_config) \
REQUIRED_FUNCTION(SSL_CTX_ctrl) \
REQUIRED_FUNCTION(SSL_CTX_free) \
REQUIRED_FUNCTION(SSL_CTX_get_ex_data) \
FALLBACK_FUNCTION(SSL_is_init_finished) \
REQUIRED_FUNCTION(SSL_CTX_new) \
REQUIRED_FUNCTION(SSL_CTX_sess_set_new_cb) \
REQUIRED_FUNCTION(SSL_CTX_sess_set_remove_cb) \
LIGHTUP_FUNCTION(SSL_CTX_set_alpn_protos) \
LIGHTUP_FUNCTION(SSL_CTX_set_alpn_select_cb) \
REQUIRED_FUNCTION(SSL_CTX_set_cipher_list) \
LIGHTUP_FUNCTION(SSL_CTX_set_ciphersuites) \
REQUIRED_FUNCTION(SSL_CTX_set_client_cert_cb) \
REQUIRED_FUNCTION(SSL_CTX_set_ex_data) \
REQUIRED_FUNCTION(SSL_CTX_set_quiet_shutdown) \
FALLBACK_FUNCTION(SSL_CTX_set_options) \
FALLBACK_FUNCTION(SSL_CTX_set_security_level) \
......@@ -490,6 +494,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(SSL_get_finished) \
REQUIRED_FUNCTION(SSL_get_peer_cert_chain) \
REQUIRED_FUNCTION(SSL_get_peer_finished) \
REQUIRED_FUNCTION(SSL_get_servername) \
REQUIRED_FUNCTION(SSL_get_SSL_CTX) \
REQUIRED_FUNCTION(SSL_get_version) \
LIGHTUP_FUNCTION(SSL_get0_alpn_selected) \
......@@ -501,6 +506,9 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(SSL_read) \
REQUIRED_FUNCTION(SSL_renegotiate) \
REQUIRED_FUNCTION(SSL_renegotiate_pending) \
REQUIRED_FUNCTION(SSL_SESSION_free) \
LIGHTUP_FUNCTION(SSL_SESSION_get0_hostname) \
LIGHTUP_FUNCTION(SSL_SESSION_set1_hostname) \
FALLBACK_FUNCTION(SSL_session_reused) \
REQUIRED_FUNCTION(SSL_set_accept_state) \
REQUIRED_FUNCTION(SSL_set_bio) \
......@@ -510,6 +518,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(SSL_set_connect_state) \
REQUIRED_FUNCTION(SSL_set_ex_data) \
FALLBACK_FUNCTION(SSL_set_options) \
REQUIRED_FUNCTION(SSL_set_session) \
REQUIRED_FUNCTION(SSL_set_verify) \
REQUIRED_FUNCTION(SSL_shutdown) \
LEGACY_FUNCTION(SSL_state) \
......@@ -931,12 +940,16 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define SSL_CTX_config SSL_CTX_config_ptr
#define SSL_CTX_ctrl SSL_CTX_ctrl_ptr
#define SSL_CTX_free SSL_CTX_free_ptr
#define SSL_CTX_get_ex_data SSL_CTX_get_ex_data_ptr
#define SSL_CTX_new SSL_CTX_new_ptr
#define SSL_CTX_sess_set_new_cb SSL_CTX_sess_set_new_cb_ptr
#define SSL_CTX_sess_set_remove_cb SSL_CTX_sess_set_remove_cb_ptr
#define SSL_CTX_set_alpn_protos SSL_CTX_set_alpn_protos_ptr
#define SSL_CTX_set_alpn_select_cb SSL_CTX_set_alpn_select_cb_ptr
#define SSL_CTX_set_cipher_list SSL_CTX_set_cipher_list_ptr
#define SSL_CTX_set_ciphersuites SSL_CTX_set_ciphersuites_ptr
#define SSL_CTX_set_client_cert_cb SSL_CTX_set_client_cert_cb_ptr
#define SSL_CTX_set_ex_data SSL_CTX_set_ex_data_ptr
#define SSL_CTX_set_options SSL_CTX_set_options_ptr
#define SSL_CTX_set_quiet_shutdown SSL_CTX_set_quiet_shutdown_ptr
#define SSL_CTX_set_security_level SSL_CTX_set_security_level_ptr
......@@ -953,6 +966,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define SSL_get_finished SSL_get_finished_ptr
#define SSL_get_peer_cert_chain SSL_get_peer_cert_chain_ptr
#define SSL_get_peer_finished SSL_get_peer_finished_ptr
#define SSL_get_servername SSL_get_servername_ptr
#define SSL_get_SSL_CTX SSL_get_SSL_CTX_ptr
#define SSL_get_version SSL_get_version_ptr
#define SSL_get0_alpn_selected SSL_get0_alpn_selected_ptr
......@@ -966,6 +980,9 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define SSL_read SSL_read_ptr
#define SSL_renegotiate SSL_renegotiate_ptr
#define SSL_renegotiate_pending SSL_renegotiate_pending_ptr
#define SSL_SESSION_free SSL_SESSION_free_ptr
#define SSL_SESSION_get0_hostname SSL_SESSION_get0_hostname_ptr
#define SSL_SESSION_set1_hostname SSL_SESSION_set1_hostname_ptr
#define SSL_session_reused SSL_session_reused_ptr
#define SSL_set_accept_state SSL_set_accept_state_ptr
#define SSL_set_bio SSL_set_bio_ptr
......@@ -975,6 +992,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define SSL_set_connect_state SSL_set_connect_state_ptr
#define SSL_set_ex_data SSL_set_ex_data_ptr
#define SSL_set_options SSL_set_options_ptr
#define SSL_set_session SSL_set_session_ptr
#define SSL_set_verify SSL_set_verify_ptr
#define SSL_shutdown SSL_shutdown_ptr
#define SSL_state SSL_state_ptr
......
......@@ -81,6 +81,8 @@ int32_t X509_get_version(const X509* x509);
int X509_set1_notAfter(X509* x509, const ASN1_TIME*);
int X509_set1_notBefore(X509* x509, const ASN1_TIME*);
int32_t X509_up_ref(X509* x509);
const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s);
int SSL_SESSION_set1_hostname(SSL_SESSION *s, const char *hostname);
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM
int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername);
......
......@@ -623,8 +623,21 @@ void CryptoNative_SslSetVerifyPeer(SSL* ssl)
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback);
}
void CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode)
int CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode, SslCtxNewSessionCallback newSessionCb, SslCtxRemoveSessionCallback removeSessionCb)
{
int retValue = 1;
if (mode && !API_EXISTS(SSL_SESSION_get0_hostname))
{
// Disable caching on old OpenSSL.
// While TLS resume is optional, none of this is critical.
mode = 0;
if (newSessionCb != NULL || removeSessionCb != NULL)
{
// Indicate unwillingness to restore sessions
retValue = 0;
}
}
// void shim functions don't lead to exceptions, so skip the unconditional error clearing.
// We never reuse same CTX for both client and server
......@@ -633,6 +646,60 @@ void CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode)
{
SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
}
if (newSessionCb != NULL)
{
SSL_CTX_sess_set_new_cb(ctx, newSessionCb);
}
if (removeSessionCb != NULL)
{
SSL_CTX_sess_set_remove_cb(ctx, removeSessionCb);
}
return retValue;
}
const char* CryptoNative_SslGetServerName(SSL* ssl)
{
return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
}
int32_t CryptoNative_SslSetSession(SSL* ssl, SSL_SESSION* session)
{
return SSL_set_session(ssl, session);
}
void CryptoNative_SslSessionFree(SSL_SESSION* session)
{
SSL_SESSION_free(session);
}
const char* CryptoNative_SslSessionGetHostname(SSL_SESSION* session)
{
#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0
if (API_EXISTS(SSL_SESSION_get0_hostname))
{
return SSL_SESSION_get0_hostname(session);
}
#else
(void*)session;
#endif
return NULL;
}
int CryptoNative_SslSessionSetHostname(SSL_SESSION* session, const char* hostname)
{
#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0
if (API_EXISTS(SSL_SESSION_set1_hostname))
{
SSL_SESSION_set1_hostname(session, hostname);
}
#else
(void*)session;
(const void*)hostname;
#endif
return 0;
}
int32_t CryptoNative_SslCtxSetEncryptionPolicy(SSL_CTX* ctx, EncryptionPolicy policy)
......@@ -855,7 +922,7 @@ void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb,
#endif
}
static int client_certificate_cb(SSL *ssl, void* state)
static int client_certificate_cb(SSL* ssl, void* state)
{
(void*)ssl;
(void*)state;
......@@ -883,7 +950,7 @@ void CryptoNative_SslSetPostHandshakeAuth(SSL* ssl, int32_t val)
#endif
}
int32_t CryptoNative_SslSetData(SSL* ssl, void *ptr)
int32_t CryptoNative_SslSetData(SSL* ssl, void* ptr)
{
ERR_clear_error();
return SSL_set_ex_data(ssl, 0, ptr);
......@@ -895,6 +962,16 @@ void* CryptoNative_SslGetData(SSL* ssl)
return SSL_get_ex_data(ssl, 0);
}
int32_t CryptoNative_SslCtxSetData(SSL_CTX* ctx, void* ptr)
{
return SSL_CTX_set_ex_data(ctx, 0, ptr);
}
void* CryptoNative_SslCtxGetData(SSL_CTX* ctx)
{
return SSL_CTX_get_ex_data(ctx, 0);
}
int32_t CryptoNative_SslSetAlpnProtos(SSL* ssl, const uint8_t* protos, uint32_t protos_len)
{
ERR_clear_error();
......@@ -959,7 +1036,7 @@ int32_t CryptoNative_SslGetCurrentCipherId(SSL* ssl, int32_t* cipherId)
}
// This function generates key pair and creates simple certificate.
static int MakeSelfSignedCertificate(X509 * cert, EVP_PKEY* evp)
static int MakeSelfSignedCertificate(X509* cert, EVP_PKEY* evp)
{
RSA* rsa = NULL;
ASN1_TIME* time = ASN1_TIME_new();
......
......@@ -117,6 +117,13 @@ typedef int32_t (*SslCtxSetAlpnCallback)(SSL* ssl,
const uint8_t* in,
uint32_t inlen,
void* arg);
// the function pointer used for new session
typedef int32_t (*SslCtxNewSessionCallback)(SSL* ssl, SSL_SESSION* sesssion);
// the function pointer used for new session
typedef void (*SslCtxRemoveSessionCallback)(SSL_CTX* ctx, SSL_SESSION* sesssion);
/*
Ensures that libssl is correctly initialized and ready to use.
*/
......@@ -152,10 +159,36 @@ Requests that client sends Post-Handshake Authentication extension in ClientHell
*/
PALEXPORT void CryptoNative_SslSetPostHandshakeAuth(SSL* ssl, int32_t val);
/*=======
/*
Sets session caching. 0 is disabled.
*/
PALEXPORT void CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode);
PALEXPORT int CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode, SslCtxNewSessionCallback newCb, SslCtxRemoveSessionCallback removeCb);
/*
Returns name associated with given ssl session.
OpenSSL holds reference to it and it must not be freed.
*/
PALEXPORT const char* CryptoNative_SslGetServerName(SSL* ssl);
/*
This function will attach existing ssl session for possible TLS resume.
*/
PALEXPORT int32_t CryptoNative_SslSetSession(SSL* ssl, SSL_SESSION* session);
/*
* Frees SSL session.
*/
PALEXPORT void CryptoNative_SslSessionFree(SSL_SESSION* session);
/*
* Get name associated with given SSL_SESSION.
*/
PALEXPORT const char* CryptoNative_SslSessionGetHostname(SSL_SESSION* session);
/*
* Associate name with given SSL_SESSION.
*/
PALEXPORT int CryptoNative_SslSessionSetHostname(SSL_SESSION* session, const char* hostname);
/*
Shims the SSL_new method.
......@@ -332,7 +365,7 @@ PALEXPORT void CryptoNative_SslCtxSetQuietShutdown(SSL_CTX* ctx);
/*
Shims the SSL_set_quiet_shutdown method.
*/
PALEXPORT void CryptoNative_SslSetQuietShutdown(SSL* ctx, int mode);
PALEXPORT void CryptoNative_SslSetQuietShutdown(SSL* ssl, int mode);
/*
Shims the SSL_get_client_CA_list method.
......@@ -349,13 +382,23 @@ PALEXPORT void CryptoNative_SslSetVerifyPeer(SSL* ssl);
/*
Shims SSL_set_ex_data to attach application context.
*/
PALEXPORT int32_t CryptoNative_SslSetData(SSL* ssl, void *ptr);
PALEXPORT int32_t CryptoNative_SslSetData(SSL* ssl, void* ptr);
/*
Shims SSL_get_ex_data to retrieve application context.
*/
PALEXPORT void* CryptoNative_SslGetData(SSL* ssl);
/*
Shims SSL_CTX_set_ex_data to attach application context.
*/
PALEXPORT int32_t CryptoNative_SslCtxSetData(SSL_CTX* ctx, void* ptr);
/*
Shims SSL_CTX_get_ex_data to retrieve application context.
*/
PALEXPORT void* CryptoNative_SslCtxGetData(SSL_CTX* ctx);
/*
Sets the specified encryption policy on the SSL_CTX.
......@@ -417,7 +460,7 @@ PALEXPORT int32_t CryptoNative_SslAddClientCAs(SSL* ssl, X509** x509s, uint32_t
/*
Shims the ssl_ctx_set_alpn_select_cb method.
*/
PALEXPORT void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb, void *arg);
PALEXPORT void CryptoNative_SslCtxSetAlpnSelectCb(SSL_CTX* ctx, SslCtxSetAlpnCallback cb, void* arg);
/*
Shims the ssl_set_alpn_protos method.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册