File: XmlEncryption\CertificateResolver.cs
Web Access
Project: src\src\DataProtection\DataProtection\src\Microsoft.AspNetCore.DataProtection.csproj (Microsoft.AspNetCore.DataProtection)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Shared;
 
namespace Microsoft.AspNetCore.DataProtection.XmlEncryption;
 
/// <summary>
/// A default implementation of <see cref="ICertificateResolver"/> that looks in the current user
/// and local machine certificate stores.
/// </summary>
public class CertificateResolver : ICertificateResolver
{
    /// <summary>
    /// Locates an <see cref="X509Certificate2"/> given its thumbprint.
    /// </summary>
    /// <param name="thumbprint">The thumbprint (as a hex string) of the certificate to resolve.</param>
    /// <returns>The resolved <see cref="X509Certificate2"/>, or null if the certificate cannot be found.</returns>
    public virtual X509Certificate2? ResolveCertificate(string thumbprint)
    {
        ArgumentNullThrowHelper.ThrowIfNull(thumbprint);
 
        if (String.IsNullOrEmpty(thumbprint))
        {
            throw Error.Common_ArgumentCannotBeNullOrEmpty(nameof(thumbprint));
        }
 
        return GetCertificateFromStore(StoreLocation.CurrentUser, thumbprint)
            ?? GetCertificateFromStore(StoreLocation.LocalMachine, thumbprint);
    }
 
    private static X509Certificate2? GetCertificateFromStore(StoreLocation location, string thumbprint)
    {
        var store = new X509Store(location);
        try
        {
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            var matchingCerts = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: true);
            return (matchingCerts != null && matchingCerts.Count > 0)
                ? matchingCerts[0]
                : null;
        }
        catch (CryptographicException)
        {
            // Suppress first-chance exceptions when opening the store.
            // For example, LocalMachine\My is not supported on Linux yet and will throw on Open(),
            // but there isn't a good way to detect this without attempting to open the store.
            // See https://github.com/dotnet/corefx/issues/3690.
            return null;
        }
        finally
        {
            store.Close();
        }
    }
}