dotnet/wpf · error · CryptographicException

SR.DigSigDuplicateCertificate

Error message

SR.DigSigDuplicateCertificate

What it means

GetPrivateKeyForSigning, when given only a certificate without an accessible private key, searches the personal certificate store by thumbprint for a matching cert with a private key. If more than one certificate with that thumbprint is found, CryptographicException(SR.DigSigDuplicateCertificate) is thrown, because the correct private key cannot be determined unambiguously.

Solutions

  1. Remove the duplicate certificate so only one copy with that thumbprint remains (certmgr.msc → delete the redundant entry).
  2. Pass a certificate instance whose PrivateKey is already available so the store lookup is skipped.
  3. Narrow the store selection by opening only one store location when resolving the signer.
  4. Rebuild a clean certificate store on the affected machine and re-import the certificate once.

Example fix

// before: resolves via store, duplicates present
dsm.Sign(toSign, publicOnlyCert);
// after: supply cert with private key
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, thumb, true)[0];
dsm.Sign(toSign, cert);
Defensive patterns

Strategy: try-catch

Validate before calling

using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
int dup = store.Certificates.Find(X509FindType.FindByThumbprint, signer.Thumbprint, true).Count;
bool ok = dup == 1;

Type guard

static bool SingleStoreMatch(X509Certificate2 c) {
    using var s = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    s.Open(OpenFlags.ReadOnly);
    return s.Certificates.Find(X509FindType.FindByThumbprint, c.Thumbprint, true).Count == 1;
}

Try / catch

try { dsm.Sign(toSign, cert); }
catch (CryptographicException ex) when (ex.Message.Contains("Duplicate"))
{ /* dedupe store and retry once */ }

Prevention

When it happens

Trigger: Calling PackageDigitalSignatureManager.Sign with an X509Certificate2 whose private key is not available, while the CurrentUser/LocalMachine store contains two certs with identical thumbprints (e.g. the same certificate installed in more than one store).

Common situations: The same certificate imported into both CurrentUser\My and LocalMachine\My; roaming profiles duplicating store entries; certificate re-import after renewal leaving stale duplicates.

Understand the failure class

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/efd18fdc4c622b4e. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/XmlDigitalSignatureProcessor.cs:1132

        private static AsymmetricAlgorithm GetPrivateKeyForSigning(X509Certificate2 signer)
        {
            // if the certificate does not actually contain the key, we need to look it up via ThumbPrint
            Invariant.Assert(!signer.HasPrivateKey);

            // look for appropriate certificates
            X509Store store = new X509Store(StoreLocation.CurrentUser);

            try
            {
                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);

                X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;

                collection = collection.Find(X509FindType.FindByThumbprint, signer.Thumbprint, true);
                if (collection.Count > 0)
                {
                    if (collection.Count > 1)
                        throw new CryptographicException(SR.DigSigDuplicateCertificate);

                    signer = collection[0];
                }
                else
                    throw new CryptographicException(SR.DigSigCannotLocateCertificate);
            }
            finally
            {
                store.Close();
            }

            // get the corresponding AsymmetricAlgorithm
            return GetPrivateKey(signer);
        }


        /// <summary>
        /// This method validated the Reference tags as per the restrictions imposed

View on GitHub (pinned to 81131a70a4)