最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - In a digitally signed (by .NET 9) XML document, how can I alter the prefix in the generated <Signature> tag w

programmeradmin1浏览0评论

I'm using C# with .NET 9, and I need to digitally sign a XML document using a X.509 certificate. The signing process itself works perfectly. However, I've been given a very specific requirement: the <Signature> tag, which is automatically generated by .NET when computing the signature, needs to have a sch: prefix for some reason, and also the namespace needs to be different.

After a lot of trial and error I've managed to make all of that happen. However, a single line of code invalidates the signature, which is:

signedXmlWithSchPrefix.SetAttribute("xmlns:sch", customNamespace);

I need to do this in order to change the namespace to the custom one.

My question: is there any way to "tell" .NET to generate the <Signature> tag with a specific prefix and specific namespace, rather than following the standard? Because I can't change the tag after it's generated, the only way I can imagine this would work is if .NET generates the tag following my requirements.

Here is my current implementation:

public static string SignWithCertificate(string xmlFilePath, string certThumbprint)
{
    // Busca o certificado
    X509Certificate2 cert = GetCertificateFromLocalMachine(certThumbprint);

    if (cert == null || !cert.HasPrivateKey)
        throw new Exception("Certificado não encontrado.");

    // Faz o parse do XML
    XmlDocument xmlDoc = new() { PreserveWhitespace = true };
    xmlDoc.LoadXml(File.ReadAllText(xmlFilePath));

    if (xmlDoc.DocumentElement == null)
        throw new ArgumentException("Falta o elemento raíz do documento XML.");

    // Define o prefixo e namespace no documento ANTES de assinar
    string customPrefix = "sch";
    string customNamespace = ";;
    XmlNamespaceManager nsManager = new(xmlDoc.NameTable);
    nsManager.AddNamespace(customPrefix, customNamespace);

    // Adiciona as referências/transforms
    Reference reference = new() { Uri = "" };
    reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());

    // Prepara a assinatura
    SignedXml signedXml = new(xmlDoc) { SigningKey = cert.GetRSAPrivateKey() };
    Signature xmlSignature = signedXml.Signature;
    xmlSignature.SignedInfo.AddReference(reference);

    KeyInfo keyInfo = new();
    keyInfo.AddClause(new KeyInfoX509Data(cert));
    xmlSignature.KeyInfo = keyInfo;

    // Gera a assinatura
    signedXml.ComputeSignature();

    XmlElement signedXmlWithSchPrefix = signedXml.GetXml();
    signedXmlWithSchPrefix.SetAttribute("xmlns:sch", customNamespace); // <--- THIS SINGLE LINE INVALIDATES THE SIGNATURE
    signedXmlWithSchPrefix.Prefix = customPrefix;

    // Prepara o elemento XML que irá conter os dados da assinatura
    string targetNodeName = "sch:envioDocumentoWS";
    XmlNode targetNode = xmlDoc.GetElementsByTagName(targetNodeName).Item(0) ??
        throw new Exception($"Tag <{targetNodeName}> não encontrada no XML.");

    // Adiciona a assinatura no documento
    XmlNode signatureNode = xmlDoc.ImportNode(signedXmlWithSchPrefix, true);
    targetNode.AppendChild(signatureNode);

    // Salva o XML assinado (mesmo nome do arquivo original, seguido de .signed.xml)
    return SaveSignedXml(xmlDoc, xmlFilePath);
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论