private XmlDocument SignSmev2(GostFlavor gostFlavor, XmlDocument doc, X509Certificate2 certificate) { XmlNode root = doc.SelectSingleNode("/*"); string rootPrefix = root?.Prefix; //----------------------------------------------------------------------------------------------CREATE STRUCTURE XmlDocument tDoc = AddTemplate(doc, certificate); //----------------------------------------------------------------------------------------------ROOT PREFIX XmlElement bodyElement = tDoc.GetElementsByTagName(rootPrefix + ":Body")[0] as XmlElement; string referenceUri = bodyElement?.GetAttribute("wsu:Id"); //----------------------------------------------------------------------------------------------SignedXML CREATE //нужен для корректной отработки wsu:reference Smev2SignedXml signedXml = new Smev2SignedXml(tDoc) { SigningKey = certificate.PrivateKey }; //----------------------------------------------------------------------------------------------REFERNCE Reference reference = new Reference { #pragma warning disable 612 DigestMethod = GostAlgorithmSelector.GetHashAlgorithmDescriptor(gostFlavor), //CPSignedXml.XmlDsigGost3411UrlObsolete, #pragma warning restore 612 Uri = "#" + referenceUri }; XmlDsigExcC14NTransform c14 = new XmlDsigExcC14NTransform(); reference.AddTransform(c14); signedXml.AddReference(reference); //----------------------------------------------------------------------------------------------SIGNATURE SETUP signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; #pragma warning disable 612 signedXml.SignedInfo.SignatureMethod = GostAlgorithmSelector.GetSignatureAlgorithmDescriptor(gostFlavor); //CPSignedXml.XmlDsigGost3410UrlObsolete; #pragma warning disable 612 //----------------------------------------------------------------------------------------------KEYINFO KeyInfo keyInfo = new KeyInfo(); KeyInfoX509Data x509KeyInfo = new KeyInfoX509Data(certificate); keyInfo.AddClause(x509KeyInfo); signedXml.KeyInfo = keyInfo; //----------------------------------------------------------------------------------------------SIGN DOCUMENT signedXml.ComputeSignature(); //----------------------------------------------------------------------------------------------GET XML XmlElement xmlDigitalSignature = signedXml.GetXml(); //----------------------------------------------------------------------------------------------APPEND SIGNATURE TAGS tDoc.GetElementsByTagName("Signature")[0].PrependChild( tDoc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignatureValue")[0], true)); tDoc.GetElementsByTagName("Signature")[0].PrependChild( tDoc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignedInfo")[0], true)); ((XmlElement)tDoc.GetElementsByTagName("Signature")[0]).SetAttribute("xmlns", DS_NS); return(tDoc); }
public static bool VerifySignature(SignatureType mode, XmlDocument message, X509Certificate2 cert = null, string certificateThumb = null, string nodeId = null) { SignedXml signedXml = new SignedXml(message); Smev2SignedXml smev2SignedXml = null; Dictionary <string, XmlElement> signatures = new Dictionary <string, XmlElement>(); XmlNodeList signaturesInDoc = message.GetElementsByTagName( "Signature", SignedXml.XmlDsigNamespaceUrl ); if (signaturesInDoc.Count < 1) { throw new Exception($"NO_SIGNATURES_FOUND] No signatures found in the input file."); } signatures = signaturesInDoc .Cast <XmlElement>() .ToDictionary((elt) => { XNamespace ns = elt.GetXElement().Name.Namespace; string sigRef = elt.GetXElement().Descendants(ns + "Reference").First().Attributes("URI").First().Value; return(elt.GetXElement().Descendants(ns + "Reference").First().Attributes("URI").First().Value.Replace("#", "")); }, (elt => elt) ); if (!string.IsNullOrEmpty(nodeId) && !signatures.ContainsKey(nodeId)) { throw new Exception($"REFERENCED_SIGNATURE_NOT_FOUND] Referenced signature (-node_id=<{nodeId}>) not found in the input file."); } switch (mode) { case SignatureType.Smev2BaseDetached: smev2SignedXml = new Smev2SignedXml(message); try { smev2SignedXml.LoadXml(!string.IsNullOrEmpty(nodeId) ? signatures[nodeId] : signatures["body"]); } catch (Exception e) { throw new Exception($"CERTIFICATE_CONTENT_CORRUPTED] <X509Certificate> node content appears to be corrupted. Message: {e.Message}"); } XmlNodeList referenceList = smev2SignedXml.KeyInfo .GetXml() .GetElementsByTagName("Reference", WSSecurityWSSENamespaceUrl); if (referenceList.Count == 0) { throw new Exception("SMEV2_CERTIFICATE_REFERENCE_NOT_FOUND] No certificate reference found in input file"); } string binaryTokenReference = ((XmlElement)referenceList[0]).GetAttribute("URI"); if (string.IsNullOrEmpty(binaryTokenReference) || binaryTokenReference[0] != '#') { throw new Exception("SMEV2_MALFORMED_CERTIFICATE_REFERENCE] Certificate reference appears to be malformed"); } XmlElement binaryTokenElement = smev2SignedXml.GetIdElement(message, binaryTokenReference.Substring(1)); if (binaryTokenElement == null) { throw new Exception($"SMEV2_CERTIFICATE_NOT_FOUND] Referenced certificate not found. Reference: <{binaryTokenReference.Substring(1)}>"); } try { cert = new X509Certificate2(Convert.FromBase64String(binaryTokenElement.InnerText)); } catch (Exception e) { throw new Exception($"SMEV2_CERTIFICATE_CORRUPTED] Smev2 certificate node content appears to be corrupted. Message: {e.Message}"); } break; case SignatureType.Smev2ChargeEnveloped: if (signaturesInDoc.Count > 1) { throw new Exception($"CHARGE_TOO_MANY_SIGNATURES_FOUND] More than one signature found. Found: {signaturesInDoc.Count} sigantures."); } if (!_chargeStructureOk(message)) { throw new Exception($"CHARGE_MALFORMED_DOCUMENT] Document structure is malformed. <Signature> node must be either root node descendant or root node descentant descendant."); } try { signedXml.LoadXml(signatures.First().Value); } catch (Exception e) { throw new Exception($"CERTIFICATE_CONTENT_CORRUPTED] <X509Certificate> node content appears to be corrupted. Message: {e.Message}"); } break; case SignatureType.Smev2SidebysideDetached: case SignatureType.Smev3BaseDetached: case SignatureType.Smev3SidebysideDetached: try { signedXml.LoadXml(!string.IsNullOrEmpty(nodeId) ? signatures[nodeId] : signatures.First().Value); } catch (Exception e) { throw new Exception($"CERTIFICATE_CONTENT_CORRUPTED] <X509Certificate> node content appears to be corrupted. Message: {e.Message}"); } break; case SignatureType.SigDetached: case SignatureType.Smev3Ack: throw new Exception($"UNSUPPORTED_SIGNATURE_TYPE] Signature type <{mode}> is unsupported. Possible values are : <smev2_base.enveloped>, <smev2_charge.enveloped>, <smev2_sidebyside.detached>, <smev3_base.detached>"); } bool result = smev2SignedXml == null ? cert == null?signedXml.CheckSignature() : signedXml.CheckSignature(cert, true) : smev2SignedXml.CheckSignature(cert.PublicKey.Key); return(result); }