internal static void CacheCredential(SafeFreeCredentials newHandle) { try { SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle); if (newRef == null) { return; } unchecked { int index = Interlocked.Increment(ref s_current) & c_MaxCacheSize; newRef = Interlocked.Exchange <SafeCredentialReference>(ref s_cacheSlots[index], newRef); } newRef?.Dispose(); } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { if (NetEventSource.IsEnabled) { NetEventSource.Fail(null, $"Attempted to throw: {e}"); } } } }
internal static void CacheCredential(SafeFreeCredentials newHandle) { try { SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle); if (newRef == null) { return; } unchecked { int index = Interlocked.Increment(ref _Current) & c_MaxCacheSize; newRef = Interlocked.Exchange <SafeCredentialReference>(ref _CacheSlots[index], newRef); } if (newRef != null) { newRef.Close(); } } catch (Exception e) { if (!NclUtilities.IsFatal(e)) { GlobalLog.Assert("SSPIHandlCache", "Attempted to throw: " + e.ToString()); } } }
internal static void CacheCredential(SafeFreeCredentials newHandle) { try { SafeCredentialReference?newRef = SafeCredentialReference.CreateReference(newHandle); if (newRef == null) { return; } int index = Interlocked.Increment(ref s_current) & c_MaxCacheSize; #pragma warning disable CS8601 // Possible null reference assignment. newRef = Interlocked.Exchange <SafeCredentialReference>(ref s_cacheSlots[index], newRef); #pragma warning restore CS8601 // Possible null reference assignment. newRef?.Dispose(); } catch (Exception e) { if (NetEventSource.Log.IsEnabled() && !ExceptionCheck.IsFatal(e)) { NetEventSource.Error(null, $"Attempted to throw: {e}"); } } }
// // The app is calling this method after starting an SSL handshake. // // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor. // internal static void CacheCredential(SafeFreeCredentials creds, byte[]?thumbPrint, SslProtocols sslProtocols, bool isServer, EncryptionPolicy encryptionPolicy, bool sendTrustList = false) { Debug.Assert(creds != null, "creds == null"); if (creds.IsInvalid) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Refused to cache an Invalid Handle {creds}, Current Cache Count = {s_cachedCreds.Count}"); } return; } SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList); SafeFreeCredentials?credentials = GetCachedCredential(key); DateTime utcNow = DateTime.UtcNow; if (credentials == null || credentials.IsClosed || credentials.IsInvalid || credentials.Expiry < utcNow) { lock (s_cachedCreds) { credentials = GetCachedCredential(key); if (credentials == null || credentials.IsClosed || credentials.IsInvalid || credentials.Expiry < utcNow) { SafeCredentialReference?cached = SafeCredentialReference.CreateReference(creds); if (cached == null) { // Means the handle got closed in between, return it back and let caller deal with the issue. return; } s_cachedCreds[key] = cached; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Caching New Handle = {creds}, Current Cache Count = {s_cachedCreds.Count}"); } ShrinkCredentialCache(); } else { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() (locked retry) Found already cached Handle = {credentials}"); } } } } else { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() Ignoring incoming handle = {creds} since found already cached Handle = {credentials}"); } }
internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SchProtocols allowedProtocols, EncryptionPolicy encryptionPolicy) { if (!creds.IsInvalid) { object obj2 = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy); SafeCredentialReference reference = s_CachedCreds[obj2] as SafeCredentialReference; if (((reference == null) || reference.IsClosed) || reference._Target.IsInvalid) { lock (s_CachedCreds) { reference = s_CachedCreds[obj2] as SafeCredentialReference; if ((reference == null) || reference.IsClosed) { reference = SafeCredentialReference.CreateReference(creds); if (reference != null) { s_CachedCreds[obj2] = reference; if ((s_CachedCreds.Count % 0x20) == 0) { DictionaryEntry[] array = new DictionaryEntry[s_CachedCreds.Count]; s_CachedCreds.CopyTo(array, 0); for (int i = 0; i < array.Length; i++) { reference = array[i].Value as SafeCredentialReference; if (reference != null) { creds = reference._Target; reference.Close(); if ((!creds.IsClosed && !creds.IsInvalid) && ((reference = SafeCredentialReference.CreateReference(creds)) != null)) { s_CachedCreds[array[i].Key] = reference; } else { s_CachedCreds.Remove(array[i].Key); } } } } } } } } } }
static void ShrinkCredentialCache() { // // A simplest way of preventing infinite cache grows. // // Security relief (DoS): // A number of active creds is never greater than a number of _outstanding_ // security sessions, i.e. SSL connections. // So we will try to shrink cache to the number of active creds once in a while. // // We won't shrink cache in the case when NO new handles are coming to it. // if ((s_cachedCreds.Count % CheckExpiredModulo) == 0) { KeyValuePair <SslCredKey, SafeCredentialReference>[] toRemoveAttempt = s_cachedCreds.ToArray(); for (int i = 0; i < toRemoveAttempt.Length; ++i) { SafeCredentialReference?cahced = toRemoveAttempt[i].Value; SafeFreeCredentials? creds = cahced.Target; if (creds == null) { s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out _); continue; } cahced.Dispose(); cahced = SafeCredentialReference.CreateReference(creds); if (cahced != null) { s_cachedCreds[toRemoveAttempt[i].Key] = cahced; } else { s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out _); } } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Scavenged cache, New Cache Count = {s_cachedCreds.Count}"); } } }
internal static void CacheCredential(SafeFreeCredentials newHandle) { try { SafeCredentialReference reference = SafeCredentialReference.CreateReference(newHandle); if (reference != null) { int index = Interlocked.Increment(ref _Current) & 0x1f; reference = Interlocked.Exchange <SafeCredentialReference>(ref _CacheSlots[index], reference); if (reference != null) { reference.Close(); } } } catch (Exception exception) { NclUtilities.IsFatal(exception); } }
internal static void CacheCredential(SafeFreeCredentials newHandle) { try { SafeCredentialReference?newRef = SafeCredentialReference.CreateReference(newHandle); if (newRef == null) { return; } int index = Interlocked.Increment(ref s_current) & MaxCacheSize; Interlocked.Exchange(ref s_cacheSlots[index], newRef)?.Dispose(); } catch (Exception e) { if (NetEventSource.Log.IsEnabled() && !ExceptionCheck.IsFatal(e)) { NetEventSource.Error(null, $"Attempted to throw: {e}"); } } }
// // The app is calling this method after starting an SSL handshake. // // ATTN: The thumbPrint must be from inspected and possibly cloned user Cert object or we get a security hole in SslCredKey ctor. // internal static void CacheCredential(SafeFreeCredentials creds, byte[]?thumbPrint, SslProtocols sslProtocols, bool isServer, EncryptionPolicy encryptionPolicy) { if (creds == null) { NetEventSource.Fail(null, "creds == null"); } if (creds !.IsInvalid) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Refused to cache an Invalid Handle {creds}, Current Cache Count = {s_cachedCreds.Count}"); } return; } var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy); SafeCredentialReference?cached; if (!s_cachedCreds.TryGetValue(key, out cached) || cached.IsClosed || cached.Target.IsInvalid) { lock (s_cachedCreds) { if (!s_cachedCreds.TryGetValue(key, out cached) || cached.IsClosed) { cached = SafeCredentialReference.CreateReference(creds); if (cached == null) { // Means the handle got closed in between, return it back and let caller deal with the issue. return; } s_cachedCreds[key] = cached; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Caching New Handle = {creds}, Current Cache Count = {s_cachedCreds.Count}"); } // // A simplest way of preventing infinite cache grows. // // Security relief (DoS): // A number of active creds is never greater than a number of _outstanding_ // security sessions, i.e. SSL connections. // So we will try to shrink cache to the number of active creds once in a while. // // We won't shrink cache in the case when NO new handles are coming to it. // if ((s_cachedCreds.Count % CheckExpiredModulo) == 0) { KeyValuePair <SslCredKey, SafeCredentialReference>[] toRemoveAttempt = s_cachedCreds.ToArray(); for (int i = 0; i < toRemoveAttempt.Length; ++i) { cached = toRemoveAttempt[i].Value; if (cached != null) { creds = cached.Target; cached.Dispose(); if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null) { s_cachedCreds[toRemoveAttempt[i].Key] = cached; } else { s_cachedCreds.TryRemove(toRemoveAttempt[i].Key, out cached); } } } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Scavenged cache, New Cache Count = {s_cachedCreds.Count}"); } } } else if (NetEventSource.Log.IsEnabled()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() (locked retry) Found already cached Handle = {cached.Target}"); } } } } else if (NetEventSource.Log.IsEnabled()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"CacheCredential() Ignoring incoming handle = {creds} since found already cached Handle = {cached.Target}"); } } }
// // The app is calling this method after starting an SSL handshake. // // ATTN: The thumbPrint must be from inspected and possbly cloned user Cert object or we get a security hole in SslCredKey ctor. // internal static void CacheCredential(SafeFreeCredentials creds, byte[] thumbPrint, SchProtocols allowedProtocols, EncryptionPolicy encryptionPolicy) { GlobalLog.Assert(creds != null, "CacheCredential|creds == null"); if (creds.IsInvalid) { GlobalLog.Print("CacheCredential() Refused to cache an Invalid Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); return; } object key = new SslCredKey(thumbPrint, allowedProtocols, encryptionPolicy); SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference; if (cached == null || cached.IsClosed || cached._Target.IsInvalid) { lock (s_CachedCreds) { cached = s_CachedCreds[key] as SafeCredentialReference; if (cached == null || cached.IsClosed) { cached = SafeCredentialReference.CreateReference(creds); if (cached == null) { // Means the handle got closed in between, return it back and let caller deal with the issue. return; } s_CachedCreds[key] = cached; GlobalLog.Print("CacheCredential() Caching New Handle = " + creds.ToString() + ", Current Cache Count = " + s_CachedCreds.Count); // // A simplest way of preventing infinite cache grows. // // Security relief (DoS): // A number of active creds is never greater than a number of _outstanding_ // security sessions, i.e. ssl connections. // So we will try to shrink cache to the number of active creds once in a while. // // Just to make clear we won't shrink cache in the case when NO new handles are coming to it. // if ((s_CachedCreds.Count % c_CheckExpiredModulo) == 0) { DictionaryEntry[] toRemoveAttempt = new DictionaryEntry[s_CachedCreds.Count]; s_CachedCreds.CopyTo(toRemoveAttempt, 0); for (int i = 0; i < toRemoveAttempt.Length; ++i) { cached = toRemoveAttempt[i].Value as SafeCredentialReference; if (cached != null) { creds = cached._Target; cached.Close(); if (!creds.IsClosed && !creds.IsInvalid && (cached = SafeCredentialReference.CreateReference(creds)) != null) { s_CachedCreds[toRemoveAttempt[i].Key] = cached; } else { s_CachedCreds.Remove(toRemoveAttempt[i].Key); } } } GlobalLog.Print("Scavenged cache, New Cache Count = " + s_CachedCreds.Count); } } else { GlobalLog.Print("CacheCredential() (locked retry) Found already cached Handle = " + cached._Target.ToString()); } } } else { GlobalLog.Print("CacheCredential() Ignoring incoming handle = " + creds.ToString() + " since found already cached Handle = " + cached._Target.ToString()); } }