c# - exist - descargar system security cryptography xml
SignedXml.CheckSignature falla en.NET 4 pero funciona en.NET 3.5, 3 o 2 (8)
Desde .NET framework 4 / 4.5, las clases para trabajar con certificados x509 y otras características de seguridad se encuentran en System.IdentityModel.dll. Busque las clases respectivas en el espacio de nombres mencionado.
Tengo una respuesta de un servicio web de terceros. Cargué un XmlDocument con esa respuesta.
string txt = readStream.ReadToEnd();
response = new XmlDocument();
response.PreserveWhitespace = true;
response.LoadXml(txt);
return response;
Ahora me gustaría verificar que las respuestas estén firmadas usando el certificado. Tengo un VerifyXmlDoc(XmlDocument xmlDoc)
que he encontrado en msdn .
Sé que el mensaje es correcto.
public bool VerifyXmlDoc(XmlDocument xmlDoc)
{
SignedXml signed = new SignedXml(xmlDoc);
XmlNodeList signatureNodeList = xmlDoc.GetElementsByTagName("Signature");
signed.LoadXml((XmlElement)signatureNodeList[0]);
X509Certificate2 serviceCertificate = null;
foreach (KeyInfoClause clause in signed.KeyInfo)
{
if (clause is KeyInfoX509Data)
{
if (((KeyInfoX509Data)clause).Certificates.Count > 0)
{
serviceCertificate = (X509Certificate2)((KeyInfoX509Data)clause).Certificates[0];
}
}
}
bool result = signed.CheckSignature(serviceCertificate, true);
return result;
}
Si configuro el marco de destino de mi proyecto en .NET 3.5 o .NET 3 o .NET 2, funciona muy bien. El resultado es verdadero Pero si cambio el marco de destino a .NET 4, el resultado es falso. (Y tengo que usar .NET 4)
¿Alguna idea sobre cómo resolver este problema?
Este es un problema conocido. La implementación de Canonicalization entre .NET 3.5 y .NET 4.0 ha cambiado.
No sé si esto funciona en todas las firmas XML, pero los siguientes trabajos de las pruebas que he hecho.
Agregue la siguiente clase de transformación C14N a su proyecto:
public class MyXmlDsigC14NTransform: XmlDsigC14NTransform {
static XmlDocument _document;
public static XmlDocument document {
set {
_document = value;
}
}
public MyXmlDsigC14NTransform() {}
public override Object GetOutput() {
return base.GetOutput();
}
public override void LoadInnerXml(XmlNodeList nodeList) {
base.LoadInnerXml(nodeList);
}
protected override XmlNodeList GetInnerXml() {
XmlNodeList nodeList = base.GetInnerXml();
return nodeList;
}
public XmlElement GetXml() {
return base.GetXml();
}
public override void LoadInput(Object obj) {
int n;
bool fDefaultNS = true;
XmlElement element = ((XmlDocument) obj).DocumentElement;
if (element.Name.Contains("SignedInfo")) {
XmlNodeList DigestValue = element.GetElementsByTagName("DigestValue", element.NamespaceURI);
string strHash = DigestValue[0].InnerText;
XmlNodeList nodeList = _document.GetElementsByTagName(element.Name);
for (n = 0; n < nodeList.Count; n++) {
XmlNodeList DigestValue2 = ((XmlElement) nodeList[n]).GetElementsByTagName("DigestValue", ((XmlElement) nodeList[n]).NamespaceURI);
string strHash2 = DigestValue2[0].InnerText;
if (strHash == strHash2) break;
}
XmlNode node = nodeList[n];
while (node.ParentNode != null) {
XmlAttributeCollection attrColl = node.ParentNode.Attributes;
if (attrColl != null) {
for (n = 0; n < attrColl.Count; n++) {
XmlAttribute attr = attrColl[n];
if (attr.Prefix == "xmlns") {
element.SetAttribute(attr.Name, attr.Value);
} else if (attr.Name == "xmlns") {
if (fDefaultNS) {
element.SetAttribute(attr.Name, attr.Value);
fDefaultNS = false;
}
}
}
}
node = node.ParentNode;
}
}
base.LoadInput(obj);
}
}
Registre la clase utilizando el método CryptoConfig.AddAlgorithm.
CryptoConfig.AddAlgorithm(typeof(MyXmlDsigC14NTransform), "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
var message = new XmlDocument();
message.PreserveWhitespace = true;
message.Load("XmlSig.xml");
MyXmlDsigC14NTransform.document = message; // The transform class needs the xml document
// Validate signature as normal.
Deberias hacer eso.
Intente establecer explícitamente el método de Canonicalization para la propiedad SignedInfo de la clase SignedXml. Parece que ha habido un cambio en el comportamiento predeterminado aquí entre .Net 2.0 y .Net 4.0.
signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;
Referencia:
Esta respuesta
Para verificar la firma en NET 4.0+, debe cambiar el contexto de su CanonicalizationMethod, por lo tanto, debe inicializar su objeto XML firmado de la siguiente manera:
XmlNodeList signatureNodeList = xmlDoc.GetElementsByTagName("Signature");
SignedXml signedXml = new SignedXml((XmlElement)signatureNodeList[0]);
signedXml.LoadXml((XmlElement)signatureNodeList[0]);
//Then you proceed your check as usual
Resolví este problema al agregar el mismo espacio de nombres de la etiqueta Signature a SignedInfo. Me gusta esto:
Antes de:
Después:
Tuve el mismo problema, pero ninguna de esas respuestas me ayudó. En este caso, funciona o no según el sistema operativo que utilicé, no en la versión .Net.
He habilitado el registro SignedXML al agregar este código en la aplicación.config para ver qué sucedió detrás:
<system.diagnostics>
<sources>
<source name="System.Security.Cryptography.Xml.SignedXml" switchName="XmlDsigLogSwitch">
<listeners>
<add name="logFile" />
</listeners>
</source>
</sources>
<switches>
<add name="XmlDsigLogSwitch" value="Verbose" />
</switches>
<sharedListeners>
<add name="logFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="XmlDsigLog.txt"/>
</sharedListeners>
<trace autoflush="true">
<listeners>
<add name="logFile" />
</listeners>
</trace>
</system.diagnostics>
Escribió esta línea en particular:
System.Security.Cryptography.Xml.SignedXml Information: 17 : [SignedXml#033ec00f, UnsafeTransformMethod] Canonicalization method "http://www.w3.org/TR/1999/REC-xpath-19991116" is not on the safe list. Safe canonicalization methods are: "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments", "http://www.w3.org/2001/10/xml-exc-c14n#", "http://www.w3.org/2001/10/xml-exc-c14n#WithComments", "http://www.w3.org/2000/09/xmldsig#enveloped-signature", "http://www.w3.org/2000/09/xmldsig#base64", "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform", "http://www.w3.org/2002/07/decrypt#XML".
Encontré este artículo de soporte de Microsoft que intenta corregir un error introducido por la actualización de seguridad 3141780: https://support.microsoft.com/en-us/kb/3148821
En ese artículo, en la sección del Escenario 2, hay 2 soluciones, arreglé el problema aplicando la clave de registro relacionada con el Método de transformación XPath: HKEY_LOCAL_MACHINE / SOFTWARE / Microsoft.NETFramework / Security / SafeTransformMethods @ XmlDsigXPathTransform = http: //www.w3 .org / TR / 1999 / REC-xpath-19991116
// Assume the data to sign is in the data.xml file, load it, and
// set up the signature object.
XmlDocument doc = new XmlDocument();
doc.Load(@"D:/Example.xml");
SignedXml sig = new SignedXml(doc);
// Make a random RSA key, and set it on the signature for signing.
RSA key = new RSACryptoServiceProvider();
sig.SigningKey = key;
// Create a Reference to the containing document, add the enveloped
// transform, and then add the Reference to the signature
Reference refr = new Reference("");refr.AddTransform(new XmlDsigEnvelopedSignatureTransform());
sig.AddReference(refr);
// Compute the signature, add it to the XML document, and save
sig.ComputeSignature();
doc.DocumentElement.AppendChild(sig.GetXml());
doc.Save("data-signed.xml");
// Load the signed data
//XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load("data-signed.xml");
// Find the Signature element in the document
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
XmlElement sigElt = (XmlElement)doc.SelectSingleNode("//dsig:Signature", nsm);
// Load the signature for verification
//SignedXml sig = new SignedXml(doc);
sig.LoadXml(sigElt);
// Verify the signature, assume the public key part of the
// signing key is in the key variable
if (sig.CheckSignature(key))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature not valid");
public static Boolean VerifyDetachedSignature(string XmlSigFileName)
{
// Create a new XML document.
XmlDocument xmlDocument = new XmlDocument();
// Load the passed XML file into the document.
xmlDocument.Load(XmlSigFileName);
// Find the "Signature" node and create a new XmlNodeList object.
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("Signature");
// Create a new SignedXMl object.
SignedXml signedXml = new SignedXml();
// Load the signature node.
signedXml.LoadXml((XmlElement)nodeList[0]);
// Check the signature and return the result.
return signedXml.CheckSignature();
}