Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs
Comment thread
cpp11nullptr marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class CryptoProviderFactory
{
private static CryptoProviderFactory _default;
private static readonly ConcurrentDictionary<string, string> _typeToAlgorithmMap = new ConcurrentDictionary<string, string>();
private readonly ConcurrentDictionary<string, string> _customProviderTypeCache = new ConcurrentDictionary<string, string>();
private static int _defaultSignatureProviderObjectPoolCacheSize = Environment.ProcessorCount * 4;
private static string _typeofAsymmetricSignatureProvider = typeof(AsymmetricSignatureProvider).ToString();
private static string _typeofSymmetricSignatureProvider = typeof(SymmetricSignatureProvider).ToString();
Expand Down Expand Up @@ -92,6 +93,7 @@ public CryptoProviderFactory(CryptoProviderFactory other)
CryptoProviderCache = new InMemoryCryptoProviderCache() { CryptoProviderFactory = this };
CustomCryptoProvider = other.CustomCryptoProvider;
CacheSignatureProviders = other.CacheSignatureProviders;
CacheCustomProviders = other.CacheCustomProviders;
SignatureProviderObjectPoolCacheSize = other.SignatureProviderObjectPoolCacheSize;
}

Expand All @@ -115,6 +117,18 @@ public CryptoProviderFactory(CryptoProviderFactory other)
[DefaultValue(true)]
public bool CacheSignatureProviders { get; set; } = DefaultCacheSignatureProviders;

/// <summary>
/// Gets or sets a bool controlling if <see cref="SignatureProvider"/> instances created by <see cref="CustomCryptoProvider"/>
/// should be cached. Default is <see langword="false"/>.
/// </summary>
/// <remarks>
/// When <see langword="true"/>, signature providers returned by <see cref="ICryptoProvider.Create(string, object[])"/>
/// are cached using the same <see cref="CryptoProviderCache"/> used for built-in providers. This avoids
/// repeated provider creation and key materialisation on every signature validation.
/// </remarks>
[DefaultValue(false)]
public bool CacheCustomProviders { get; set; }
Comment thread
cpp11nullptr marked this conversation as resolved.

/// <summary>
/// Gets or sets the maximum size of the object pool used by the SignatureProvider that are used for crypto objects.
/// </summary>
Expand Down Expand Up @@ -598,6 +612,23 @@ private SignatureProvider CreateSignatureProvider(
SignatureProvider signatureProvider;
if (CustomCryptoProvider != null && CustomCryptoProvider.IsSupportedAlgorithm(algorithm, key, willCreateSignatures))
{
if (CacheCustomProviders && CacheSignatureProviders && cacheProvider)
{
// Try cache lookup first using the remembered provider type from a previous Create call.
string cacheTypeKey = CustomCryptoProvider.GetType().ToString() + "-" + algorithm;
Comment thread
iNinja marked this conversation as resolved.
if (_customProviderTypeCache.TryGetValue(cacheTypeKey, out string providerType)
&& CryptoProviderCache.TryGetSignatureProvider(
key,
algorithm,
providerType,
willCreateSignatures,
out SignatureProvider cachedProvider))
{
cachedProvider.AddRef();
return cachedProvider;
}
}

signatureProvider = CustomCryptoProvider.Create(algorithm, key, willCreateSignatures) as SignatureProvider;
if (signatureProvider == null)
throw LogHelper.LogExceptionMessage(
Expand All @@ -608,6 +639,17 @@ private SignatureProvider CreateSignatureProvider(
LogHelper.MarkAsNonPII(key.KeyId),
LogHelper.MarkAsNonPII(typeof(SignatureProvider)))));

if (CacheCustomProviders && CacheSignatureProviders && cacheProvider)
Comment thread
iNinja marked this conversation as resolved.
{
// Remember the provider type for future cache lookups.
string cacheTypeKey = CustomCryptoProvider.GetType().ToString() + "-" + algorithm;
string providerType = signatureProvider.GetType().ToString();
_customProviderTypeCache.TryAdd(cacheTypeKey, providerType);

if (ShouldCacheSignatureProvider(signatureProvider))
signatureProvider.IsCached = CryptoProviderCache.TryAdd(signatureProvider);
}

return signatureProvider;
}

Expand Down Expand Up @@ -858,9 +900,14 @@ public virtual void ReleaseSignatureProvider(SignatureProvider signatureProvider

signatureProvider.Release();
if (CustomCryptoProvider != null && CustomCryptoProvider.IsSupportedAlgorithm(signatureProvider.Algorithm))
CustomCryptoProvider.Release(signatureProvider);
{
if (!signatureProvider.IsCached)
CustomCryptoProvider.Release(signatureProvider);
}
else if (signatureProvider.CryptoProviderCache == null && signatureProvider.RefCount == 0 && !signatureProvider.IsCached)
{
signatureProvider.Dispose();
}
}
}
}
Loading