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
- Remove the duplicate certificate so only one copy with that thumbprint remains (certmgr.msc → delete the redundant entry).
- Pass a certificate instance whose PrivateKey is already available so the store lookup is skipped.
- Narrow the store selection by opening only one store location when resolving the signer.
- 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
- Keep one copy of each certificate per store location.
- Pass certificates that already carry their private key.
- Periodically audit certificate stores for duplicates.
- Avoid re-importing the same PFX repeatedly.
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Container already has Starting Part.
- FixedDocument has more than one related document structure.
- FixedPage has more than one related story fragment.
- PackageAlreadyExists
- SR.AnnotationAlreadyExists
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 imposedView on GitHub (pinned to 81131a70a4)