{"record":{"id":"e24685b43289c123","repo":"dotnet/wpf","slug":"can-only-countersign-parts-with-digital-signature","errorCode":null,"errorMessage":"Can only countersign parts with Digital Signature ContentType.","messagePattern":"Can only countersign parts with Digital Signature ContentType\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/PackageDigitalSignatureManager.cs","lineNumber":635,"sourceCode":"        /// returned signature.</remarks>\n        /// <exception cref=\"InvalidOperationException\">Cannot CounterSign an unsigned package.</exception>\n        /// <exception cref=\"ArgumentException\">signatures must be non-empty and cannot refer to parts other than signature parts.</exception>\n        /// <exception cref=\"ArgumentNullException\">Both arguments must be non-null.</exception>\n        public PackageDigitalSignature Countersign(X509Certificate certificate, IEnumerable<Uri> signatures)\n        {\n            ArgumentNullException.ThrowIfNull(certificate);\n            ArgumentNullException.ThrowIfNull(signatures);\n\n            // Counter-sign makes no sense if we are not already signed\n            if (!IsSigned)\n                throw new InvalidOperationException(SR.NoCounterSignUnsignedContainer);\n\n            // Restrict signatures to be actual signature part references\n            foreach (Uri uri in signatures)\n            {\n                PackagePart part = _container.GetPart(uri);\n                if (!part.ValidatedContentType().AreTypeAndSubTypeEqual(XmlDigitalSignatureProcessor.ContentType))\n                    throw new ArgumentException(SR.Format(SR.CanOnlyCounterSignSignatureParts, signatures));\n            }\n\n            return Sign(signatures, certificate);\n        }\n        #endregion\n\n        /// <summary>\n        /// verify all signatures - calls verify on each signature\n        /// </summary>\n        /// <param name=\"exitOnFailure\">true to exit on first failure - false to continue</param>\n        /// <remarks>register for invalid signature events</remarks>\n        public VerifyResult VerifySignatures(bool exitOnFailure)\n        {\n            VerifyResult result;\n            EnsureSignatures();\n\n            // signed?\n            if (_signatures.Count == 0)","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/PackageDigitalSignatureManager.cs#L617-L653","documentation":"The Countersign(certificate, signatures) overload validates that every URI in the signatures list refers to a package part whose content type exactly equals the XML Digital Signature content type, throwing ArgumentException (SR.CanOnlyCounterSignSignatureParts) otherwise.","triggerScenarios":"Passing URIs of non-signature parts (documents, images, relationship parts) in the signatures collection to Countersign; passing URIs copied from a different package.","commonSituations":"Confusing Countersign's URI list with the list of parts to sign (Sign's semantics); hardcoded URIs that point at ordinary content parts; URIs from a package with different part naming conventions.","solutions":["Only pass URIs obtained from PackageDigitalSignature.SignaturePart.Uri of existing signatures in this package","Filter the list to parts whose ValidatedContentType matches the XmlDSig content type before calling","Do not reuse the Sign(parts) argument lists for Countersign — they have different semantics","Catch ArgumentException and log which URI failed the content-type check"],"exampleFix":"// before\nmgr.Countersign(cert, new List<Uri> { docPartUri }); // wrong: content part, not a signature part\n// after\nvar sigUris = mgr.Signatures.Select(s => s.SignaturePart.Uri).ToList();\nmgr.Countersign(cert, sigUris);","handlingStrategy":"validation","validationCode":"foreach (Uri uri in signatures)\n{\n    var part = package.GetPart(uri);\n    if (!part.ContentType.Equals(\"application/vnd.openxmlformats-package.digital-signature+xml\", StringComparison.Ordinal))\n        throw new ArgumentException($\"Part {uri} is not a digital signature part.\");\n}","typeGuard":"bool IsSignaturePart(Package pkg, Uri uri) =>\n    pkg.PartExists(uri) &&\n    pkg.GetPart(uri).ContentType == \"application/vnd.openxmlformats-package.digital-signature+xml\";","tryCatchPattern":"try { manager.Countersign(certificate, signatures); }\ncatch (ArgumentException ex) { log.Error(\"Non-signature part passed to Countersign\", ex); }","preventionTips":["Build the URI list from PackageDigitalSignature.SignaturePart.Uri only","Remember Countersign takes signature part URIs, unlike Sign which takes content parts","Validate part content types before invoking Countersign"],"tags":["wpf","packaging","argumentexception","countersign","content-type"],"backgroundTag":"invalid-argument-value","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}