Hello, I have a problem with creating a signed file with a x509 certificate. I did create a selfsigned SSL certficate that I use to test my code.
My code produces a xml that looks like the demo file and a signed file from signing API yet when I try do verify my generated file in a JAVA API gateway where I need to send it, I get error invalid signature.
I use the XmlDsigXPathTransform, XmlDsigExcC14NTransform and XadES. Yet when I run the verification check I get always a false result from XPATH transform. I'm going on for weeks with this problem yet no solution....
Is there any way to find why the signature is invalid?
private static XmlElement SignXMLDocument(string xml, X509Certificate2 certificate, string signedXMLPath)
{
string XPathString = "not(ancestor-or-self::Signature)";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = false;
xmlDocument.Load(xml);
var signedXml = new XadesSignedXml(xmlDocument);
signedXml.Signature.Id = SignatureId;
signedXml.SigningKey = certificate.PrivateKey;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
var signatureReference = new Reference { Uri = "", };
XmlDsigXPathTransform XPathTransform = CreateXPathTransform(XPathString);
signatureReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signatureReference.AddTransform(XPathTransform);
signedXml.AddReference(signatureReference);
var signatureReference2 = new Reference { Uri = "", };
signatureReference2.AddTransform(new XmlDsigExcC14NTransform());
signatureReference2.Type = "http://uri.etsi.org/01903#SignedProperties";
signatureReference2.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signedXml.AddReference(signatureReference2);
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
signedXml.KeyInfo = keyInfo;
AddXAdESProperties(xmlDocument, signedXml, certificate);
signedXml.ComputeSignature();
signedXml.CheckSignature(certificate, true);
signedXml.CheckSignature();
bool result = VerifyXmlFile(signedXMLPath);
XmlElement signature = signedXml.GetXml();
signedXml.ComputeSignature();
string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signature, true));
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signature, true));
signedXml.CheckSignature(certificate, true);
signedXml.CheckSignature();
XmlTextWriter xmltw = new XmlTextWriter(signedXMLPath, new UTF8Encoding(false));
xmlDocument.WriteTo(xmltw);
xmltw.Close();
return signedXml.GetXml();
}
private static XmlDsigXPathTransform CreateXPathTransform(string XPathString)
{
XmlDocument doc = new XmlDocument();
XmlElement xPathElem = doc.CreateElement("XPath");
xPathElem.InnerText = XPathString;
XmlDsigXPathTransform xForm = new XmlDsigXPathTransform();
xForm.LoadInnerXml(xPathElem.SelectNodes("."));
xForm.Algorithm = SignedXml.XmlDsigXPathTransformUrl;
XmlElement xmlInTransform = xForm.GetXml();
return xForm;
}
public class XadesSignedXml : SignedXml
{
#region Public fields
public const string XmlDsigSignatureProperties = "http://uri.etsi.org/01903#SignedProperties";
public const string XadesProofOfApproval = "http://uri.etsi.org/01903/v1.2.2#ProofOfApproval";
public const string XadesPrefix = "xades";
public const string XadesNamespaceUrl = "http://uri.etsi.org/01903/v1.3.2#";
public XmlElement PropertiesNode { get; set; }
#endregion Public fields
#region Private fields
private readonly List<DataObject> _dataObjects = new List<DataObject>();
#endregion Private fields
#region Constructor
public XadesSignedXml(XmlDocument document) : base(document) { }
#endregion Constructor
#region SignedXml
public override XmlElement GetIdElement(XmlDocument document, string idValue)
{
if (String.IsNullOrEmpty(idValue)) return null;
XmlElement xmlElement = base.GetIdElement(document, idValue);
if (xmlElement != null) return xmlElement;
foreach (DataObject dataObject in _dataObjects)
{
XmlElement nodeWithSameId = findNodeWithAttributeValueIn(dataObject.Data, "Id", idValue);
if (nodeWithSameId != null)
return nodeWithSameId;
}
if (KeyInfo != null)
{
XmlElement nodeWithSameId = findNodeWithAttributeValueIn(KeyInfo.GetXml().SelectNodes("."), "Id", idValue);
if (nodeWithSameId != null)
return nodeWithSameId;
}
return null;
}
public XmlElement findNodeWithAttributeValueIn(XmlNodeList nodeList, string attributeName, string value)
{
if (nodeList.Count == 0) return null;
foreach (XmlNode node in nodeList)
{
XmlElement nodeWithSameId = findNodeWithAttributeValueIn(node, attributeName, value);
if (nodeWithSameId != null) return nodeWithSameId;
}
return null;
}
private XmlElement findNodeWithAttributeValueIn(XmlNode node, string attributeName, string value)
{
string attributeValueInNode = getAttributeValueInNodeOrNull(node, attributeName);
if ((attributeValueInNode != null) && (attributeValueInNode.Equals(value))) return (XmlElement)node;
return findNodeWithAttributeValueIn(node.ChildNodes, attributeName, value);
}
private string getAttributeValueInNodeOrNull(XmlNode node, string attributeName)
{
if (node.Attributes != null)
{
XmlAttribute attribute = node.Attributes[attributeName];
if (attribute != null) return attribute.Value;
}
return null;
}
public new void AddObject(DataObject dataObject)
{
base.AddObject(dataObject);
_dataObjects.Add(dataObject);
}
#endregion SignedXml
}
What I have tried:
Removing Xpath transformation reuslt validatuin true result yet still it don't pass API gateway. The documentation states below transformations to be used yet in demo I don't see the fillter2 transfotmarion and im not sure about ds: prefix. Many states that its not need for signatures. I'm not sure if the values are calculated good or not. Nothing I found on the internet for past weeks worked. Any possible help?
http://www.w3.org/TR/1999/REC-xpath-19991116 - not(ancestor-or-self::ds:Signature)
http://www.w3.org/2002/06/xmldsig-filter2
http://www.w3.org/2000/09/xmldsig#enveloped-signature