internal Signature(XmlElement signatureElement, ILookup <XmlElement, XmlElement> childIndex) { // store element for countersigning XmlElement = signatureElement; // parse signature _xades = Xades.Load(signatureElement); // check signature; resolve external references relative to main document string baseUri = signatureElement.OwnerDocument?.BaseURI; IsValid = _xades.CheckSignature(out X509Certificate2 certificate, u => { Uri uri = baseUri == null ? new Uri(u) : new Uri(new Uri(baseUri), u); return(File.OpenRead(uri.LocalPath)); }); // store certificate Certificate = certificate; if (certificate != null) { X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; //chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; CertificateIsValid = chain.Build(certificate); CertificateError = (CertificateIsValid == false) ? chain.ChainStatus?.First().StatusInformation.Trim() : null; CACertificate = chain.ChainElements.OfType <X509ChainElement>().LastOrDefault(x => x.Certificate.Extensions.OfType <X509BasicConstraintsExtension>().Any(y => y.CertificateAuthority))?.Certificate; } XadesSignatureProperties signatureProperties = _xades.SignatureProperties; if (signatureProperties != null) { // store date SignatureDate = _xades.SignatureProperties.SigningTime; // read signature policy if (signatureProperties.PolicyImplied) { SignaturePolicy = new SignaturePolicy(); } else if (signatureProperties.PolicyId != null) { SignaturePolicy = new SignaturePolicy(signatureProperties.PolicyId); } } // store signed item references Items = _xades.References.Select(x => new SignedItem(signatureElement, x, SignaturePolicy)).ToList(); // determine type of signature Type = Items.Any(x => x.Type == SignedItemType.Document) ? SignatureType.Document : Items.Any(x => x.Type == SignedItemType.Signature) ? SignatureType.CounterSignature : SignatureType.Generic; // parse child signatures Signatures = childIndex[signatureElement].Select(x => new Signature(x, childIndex)).ToList(); }
internal SignedItem(XmlElement signatureElement, XadesReference reference, SignaturePolicy signaturePolicy) { // determine type from reference uri Uri = reference.URI; if (Uri == "" || Uri == "#xpointer(/)") { Type = SignedItemType.Document; } else if (reference.Type == Xades.CounterSignatureRefernceType) { Type = SignedItemType.Signature; } else if (Uri[0] == '#') { string idref = Uri.Substring(1); XmlElement node = signatureElement.OwnerDocument.SelectSingleNode("//*[@id='" + idref + "' or @Id='" + idref + "']") as XmlElement; if (node != null && node.LocalName == "SignatureValue" && node.NamespaceURI == SignedXml.XmlDsigNamespaceUrl) { Type = SignedItemType.Signature; } else { Type = SignedItemType.Fragment; } } else { Type = SignedItemType.File; } // store transform Transform = new TransformSet(null, reference.TransformChain); // find or add commitment type in/to policy if (reference.CommitmentTypeId != null) { SignaturePolicy.CommitmentType commitmentType = signaturePolicy.CommitmentTypes.FirstOrDefault(x => x.Identifier == reference.CommitmentTypeId.Identifier); if (commitmentType == null) { commitmentType = new SignaturePolicy.CommitmentType() { Identifier = reference.CommitmentTypeId.Identifier, Description = reference.CommitmentTypeId.Description }; signaturePolicy.CommitmentTypes.Add(commitmentType); } CommitmentType = commitmentType; } IsValid = reference.IsValid; }
public bool Countersign(X509Certificate2 cert, List <SignedItem> items, SignaturePolicy policy) { XmlDocument xmlDocument = XmlElement.OwnerDocument; // find or add id to signature value XmlElement signatureValue = XmlElement["SignatureValue", SignedXml.XmlDsigNamespaceUrl]; if (signatureValue == null) { return(false); } string id = (signatureValue.Attributes["Id"] ?? signatureValue.Attributes["id"])?.Value; if (id == null) { HashSet <string> ids = new HashSet <string>(xmlDocument.SelectNodes("//@id | //@Id").OfType <XmlAttribute>().Select(x => x.Value)); Random rnd = new Random(); for (; ;) { id = $"signature-value-{rnd.Next():x8}"; if (!ids.Contains(id)) { break; } } signatureValue.SetAttribute("Id", id); } // find or add unsigned properties XmlElement qualifyingProperties = XmlElement.ChildNodes.OfType <XmlElement>().Where(x => x.LocalName == "Object" && x.NamespaceURI == SignedXml.XmlDsigNamespaceUrl).Select(x => x["QualifyingProperties", Xades.XadesNamespaceUrl]).SingleOrDefault(x => x != null); if (qualifyingProperties == null) { return(false); } XmlElement unsignedSignatureProperties = qualifyingProperties.GetOrCreate("UnsignedProperties", Xades.XadesNamespaceUrl).GetOrCreate("UnsignedSignatureProperties", Xades.XadesNamespaceUrl); XmlElement signatureLocation = xmlDocument.CreateElement("CounterSignature", Xades.XadesNamespaceUrl); unsignedSignatureProperties.AppendChild(signatureLocation); // create signature Xades xades = Xades.Create(xmlDocument, signatureLocation); xades.SignatureProperties.SigningTime = DateTime.UtcNow; // add policy if (policy != null) { xades.SignatureProperties.PolicyId = new ObjectIdentifier() { Identifier = policy.Identifier, Description = policy.Description }; xades.SignatureProperties.PolicyURIs = new List <string>() { policy.URI }; // todo: determine transforms, calculate digest } // add countersignature reference XadesReference reference = new XadesReference($"#{id}", TransformSet.Signature.TransformChain) { Type = Xades.CounterSignatureRefernceType }; SignedItem signatureItem = items.Single(x => x.Type == SignedItemType.Signature); if (policy != null && signatureItem.CommitmentType != null) { reference.CommitmentTypeId = new ObjectIdentifier() { Identifier = signatureItem.CommitmentType.Identifier, Description = signatureItem.CommitmentType.Description } } ; xades.References.Add(reference); // add other references foreach (SignedItem item in items.Where(x => x.Type != SignedItemType.Signature)) { reference = new XadesReference(item.Uri, item.Transform.TransformChain); if (policy != null && item.CommitmentType != null) { reference.CommitmentTypeId = new ObjectIdentifier() { Identifier = signatureItem.CommitmentType.Identifier, Description = signatureItem.CommitmentType.Description } } ; xades.References.Add(reference); } // sign string baseUri = xmlDocument.BaseURI; xades.UriResolver = u => { Uri uri = baseUri == null ? new Uri(u) : new Uri(new Uri(baseUri), u); return(File.OpenRead(uri.LocalPath)); }; XmlElement result = xades.Sign(cert); signatureLocation.AppendChild(result); return(true); } } }