_SslSessionsCache.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Net / System / Net / _SslSessionsCache.cs / 1 / _SslSessionsCache.cs

                            /*++ 
Copyright (c) Microsoft Corporation

Module Name:
 
    _SslSessionsCache.cs
 
Abstract: 
    The file implements SSL session caching mechanism based on a static table of SSL credentials
 

Author:

    Alexei Vopilov    20-Jul-2004 

Revision History: 
 

--*/ 
namespace System.Net.Security {

using System.Net;
using System.Security.Cryptography.X509Certificates; 
using System.Collections;
 
    internal static class SslSessionsCache { 

          private const int                         c_CheckExpiredModulo = 32; 
          private static Hashtable                  s_CachedCreds = new Hashtable(32);

          //
          // Uses cryptographically strong certificate thumbprint comparison 
          //
          private struct SslCredKey 
          { 
              private static readonly byte[] s_EmptyArray = new byte[0];
 
              private byte[]       _CertThumbPrint;
              private SchProtocols _AllowedProtocols;
              private int          _HashCode;
              // 
              // SECURITY: X509Certificate.GetCertHash() is virtual hence before going here
              //           the caller of this ctor has to ensure that a user cert object was inspected and 
              //           optionally cloned. 
              //
              internal  SslCredKey(byte[] thumbPrint, SchProtocols allowedProtocols) 
              {
                  _CertThumbPrint = thumbPrint == null? s_EmptyArray: thumbPrint;
                  _HashCode = 0;
                  if (thumbPrint != null) 
                  {
                      _HashCode ^= _CertThumbPrint[0]; 
                      if (1 < _CertThumbPrint.Length) 
                          _HashCode ^= (_CertThumbPrint[1] << 8);
                      if (2 < _CertThumbPrint.Length) 
                          _HashCode ^= (_CertThumbPrint[2] << 16);
                      if (3 < _CertThumbPrint.Length)
                          _HashCode ^= (_CertThumbPrint[3] << 24);
                  } 
                  _AllowedProtocols = allowedProtocols;
                  _HashCode ^= (int)_AllowedProtocols; 
              } 
              //
              public override int GetHashCode() 
              {
                  return _HashCode;
              }
              // 
              public static bool operator == (SslCredKey sslCredKey1,
                                              SslCredKey sslCredKey2) 
              { 
                  if ((object)sslCredKey1 == (object)sslCredKey2) {
                      return true; 
                  }
                  if ((object)sslCredKey1 == null || (object)sslCredKey2 == null) {
                      return false;
                  } 
                  return sslCredKey1.Equals(sslCredKey2);
              } 
              // 
              public static bool operator != (SslCredKey sslCredKey1,
                                              SslCredKey sslCredKey2) 
              {
                  if ((object)sslCredKey1 == (object)sslCredKey2) {
                      return false;
                  } 
                  if ((object)sslCredKey1 == null || (object)sslCredKey2 == null) {
                      return true; 
                  } 
                  return !sslCredKey1.Equals(sslCredKey2);
              } 
              //
              public override bool Equals(Object y)
              {
                  SslCredKey she = (SslCredKey)y; 

                  if (_CertThumbPrint.Length != she._CertThumbPrint.Length) 
                      return false; 

                  if (_HashCode != she._HashCode) 
                      return false;

                  for (int i = 0; i < _CertThumbPrint.Length; ++i)
                      if (_CertThumbPrint[i] != she._CertThumbPrint[i]) 
                          return false;
 
                  return true; 
              }
          } 


          //
          // Returns null or previously cached cred handle 
          //
          // ATTN: The returned handle can be invalid, the callers of InitializeSecurityContext and AcceptSecurityContext 
          // must be prepared to execute a backout code if the call fails. 
          //
          // Note:thumbPrint is a cryptographicaly strong hash of a certificate 
          //
          internal static SafeFreeCredentials TryCachedCredential(byte[] thumbPrint, SchProtocols allowedProtocols)
          {
              if (s_CachedCreds.Count == 0) 
              {
                  GlobalLog.Print("TryCachedCredential() Not Found, Current Cache Count = " + s_CachedCreds.Count); 
                  return null; 
              }
 
              object key = new SslCredKey(thumbPrint, allowedProtocols);

              SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference;
 
              if (cached == null || cached.IsClosed || cached._Target.IsInvalid)
              { 
                  GlobalLog.Print("TryCachedCredential() Not Found, Current Cache Count = " + s_CachedCreds.Count); 
                  return null;
              } 

              GlobalLog.Print("TryCachedCredential() Found a cached Handle = " + cached._Target.ToString());

              return 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)
          {
              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);

              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());
              } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/*++ 
Copyright (c) Microsoft Corporation

Module Name:
 
    _SslSessionsCache.cs
 
Abstract: 
    The file implements SSL session caching mechanism based on a static table of SSL credentials
 

Author:

    Alexei Vopilov    20-Jul-2004 

Revision History: 
 

--*/ 
namespace System.Net.Security {

using System.Net;
using System.Security.Cryptography.X509Certificates; 
using System.Collections;
 
    internal static class SslSessionsCache { 

          private const int                         c_CheckExpiredModulo = 32; 
          private static Hashtable                  s_CachedCreds = new Hashtable(32);

          //
          // Uses cryptographically strong certificate thumbprint comparison 
          //
          private struct SslCredKey 
          { 
              private static readonly byte[] s_EmptyArray = new byte[0];
 
              private byte[]       _CertThumbPrint;
              private SchProtocols _AllowedProtocols;
              private int          _HashCode;
              // 
              // SECURITY: X509Certificate.GetCertHash() is virtual hence before going here
              //           the caller of this ctor has to ensure that a user cert object was inspected and 
              //           optionally cloned. 
              //
              internal  SslCredKey(byte[] thumbPrint, SchProtocols allowedProtocols) 
              {
                  _CertThumbPrint = thumbPrint == null? s_EmptyArray: thumbPrint;
                  _HashCode = 0;
                  if (thumbPrint != null) 
                  {
                      _HashCode ^= _CertThumbPrint[0]; 
                      if (1 < _CertThumbPrint.Length) 
                          _HashCode ^= (_CertThumbPrint[1] << 8);
                      if (2 < _CertThumbPrint.Length) 
                          _HashCode ^= (_CertThumbPrint[2] << 16);
                      if (3 < _CertThumbPrint.Length)
                          _HashCode ^= (_CertThumbPrint[3] << 24);
                  } 
                  _AllowedProtocols = allowedProtocols;
                  _HashCode ^= (int)_AllowedProtocols; 
              } 
              //
              public override int GetHashCode() 
              {
                  return _HashCode;
              }
              // 
              public static bool operator == (SslCredKey sslCredKey1,
                                              SslCredKey sslCredKey2) 
              { 
                  if ((object)sslCredKey1 == (object)sslCredKey2) {
                      return true; 
                  }
                  if ((object)sslCredKey1 == null || (object)sslCredKey2 == null) {
                      return false;
                  } 
                  return sslCredKey1.Equals(sslCredKey2);
              } 
              // 
              public static bool operator != (SslCredKey sslCredKey1,
                                              SslCredKey sslCredKey2) 
              {
                  if ((object)sslCredKey1 == (object)sslCredKey2) {
                      return false;
                  } 
                  if ((object)sslCredKey1 == null || (object)sslCredKey2 == null) {
                      return true; 
                  } 
                  return !sslCredKey1.Equals(sslCredKey2);
              } 
              //
              public override bool Equals(Object y)
              {
                  SslCredKey she = (SslCredKey)y; 

                  if (_CertThumbPrint.Length != she._CertThumbPrint.Length) 
                      return false; 

                  if (_HashCode != she._HashCode) 
                      return false;

                  for (int i = 0; i < _CertThumbPrint.Length; ++i)
                      if (_CertThumbPrint[i] != she._CertThumbPrint[i]) 
                          return false;
 
                  return true; 
              }
          } 


          //
          // Returns null or previously cached cred handle 
          //
          // ATTN: The returned handle can be invalid, the callers of InitializeSecurityContext and AcceptSecurityContext 
          // must be prepared to execute a backout code if the call fails. 
          //
          // Note:thumbPrint is a cryptographicaly strong hash of a certificate 
          //
          internal static SafeFreeCredentials TryCachedCredential(byte[] thumbPrint, SchProtocols allowedProtocols)
          {
              if (s_CachedCreds.Count == 0) 
              {
                  GlobalLog.Print("TryCachedCredential() Not Found, Current Cache Count = " + s_CachedCreds.Count); 
                  return null; 
              }
 
              object key = new SslCredKey(thumbPrint, allowedProtocols);

              SafeCredentialReference cached = s_CachedCreds[key] as SafeCredentialReference;
 
              if (cached == null || cached.IsClosed || cached._Target.IsInvalid)
              { 
                  GlobalLog.Print("TryCachedCredential() Not Found, Current Cache Count = " + s_CachedCreds.Count); 
                  return null;
              } 

              GlobalLog.Print("TryCachedCredential() Found a cached Handle = " + cached._Target.ToString());

              return 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)
          {
              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);

              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());
              } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK