1) SignedXml 클래스로는 signature에 sha256을 사용 할 수가 없습니다.
그런데 digest는 xmlenc#sha256으로 지정해도 256비트 결과가 나오고 오류가 없더군요.
signedXml.SignedInfo.SignatureMethod = "
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
rsa-sha256일 때 발생하는 예외
System.Security.Cryptography.CryptographicException: SignatureDescription could not be created for the signature algorithm supplied.
at System.Security.Cryptography.Xml.SignedXml.ComputeSignature()
이걸 지원하지 않습니다. prefix 문제를 해결 하더라도 지원하지 않는 algorithm 때문에 에러가 날 것입니다.
관련 사이트
https://msdn.microsoft.com/en-us/library/windows/desktop/dd979768(v=vs.85).aspx
2) 서명 전에는 ds prefix가 없는 상태에서 진행합니다.
ancestor-or-self::ds:Signature => ancestor-or-self::Signature
ds:XPath => XPath
서명이 끝나면 SetPrefix()로 ds를 붙여줍니다.
제가 테스트해보니 이 함수를 그냥 쓰면 root node에는 ds가 붙지 않았고, namespace에도 붙지 않았습니다.
아래처럼 사용하세요.
signedXml.ComputeSignature();
XmlElement xmlDisigXml = signedXml.GetXml();
var nameTable = new NameTable();
XmlNamespaceManager xmlNmMgr = new XmlNamespaceManager(nameTable);
xmlNmMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
xmlNmMgr.AddNamespace("xsi", "
http://www.w3.org/2001/XMLSchema-instance");
xmlNmMgr.AddNamespace("schemaLocation", "
http://www.w3.org/2000/09/xmldsig# http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd");
var xmldsigDoc = new XmlDocument(nameTable);
xmldsigDoc.LoadXml(xmlDisigXml.OuterXml);
SetPrefix(xmldsigDoc);
테스트 코드
[Test]
public void DoDigitalSign()
{
var priKey = GetSignPrivateKey("XmlSign.Test.Resources._2010.kmPri.key", "88888888");
var signCert = new X509Certificate2(Datum.SIGNCERT);
var transformXPath = "not(self::*[name()='TaxInvoice']" +
"|ancestor-or-self::*[name()='ExchangedDocument']" +
"|ancestor-or-self::Signature)";
var transformXPath2 = "not(self::*[name()='TaxInvoice'] " +
"|ancestor-or-self::*[name()='ExchangedDocument']" +
"|ancestor-or-self::ds:Signature)";
var signedFileName = "SignedTaxInvoice_Sampl.xml";
var tbSignXml = GetResourceString("XmlSign.Test.Resources._2010.TaxInvoice_Sample.xml");
SignXmlFile(
tbSignXml,
signedFileName,
transformXPath, transformXPath2,
priKey,
signCert
);
}
const string wszURI_XMLNS_DIGSIG_RSA_SHA256 = "
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
const string wszURI_XMLNS_DIGSIG_SHA256 = "
http://www.w3.org/2001/04/xmlenc#sha256";
public void SignXmlFile(string tbSignXml, string signedFileName, string xpath, string xpath2, RSA signKey, X509Certificate2 signCert)
{
XmlDocument doc = new XmlDocument { PreserveWhitespace = true };
doc.LoadXml(tbSignXml);
var signedXml = new SignedXml(doc);
//signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.SignedInfo.SignatureMethod = wszURI_XMLNS_DIGSIG_RSA_SHA256;
//"
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; // see
https://www.sysnet.pe.kr/Default.aspx?mode=3&sub=0&pageno=0&detail=1&wid=3653
Reference reference = new Reference
{
Uri = "",
//DigestMethod = SignedXml.XmlDsigSHA1Url
DigestMethod = wszURI_XMLNS_DIGSIG_SHA256
};
reference.AddTransform(new XmlDsigC14NTransform(false));
reference.AddTransform(CreateXPathTransform(xpath));
signedXml.AddReference(reference);
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(signCert));
signedXml.KeyInfo = keyInfo;
signedXml.SigningKey = signKey;
signedXml.ComputeSignature();
XmlElement xmlDisigXml = signedXml.GetXml();
var nameTable = new NameTable();
XmlNamespaceManager xmlNmMgr = new XmlNamespaceManager(nameTable);
xmlNmMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
xmlNmMgr.AddNamespace("xsi", "
http://www.w3.org/2001/XMLSchema-instance");
xmlNmMgr.AddNamespace("schemaLocation", "
http://www.w3.org/2000/09/xmldsig# http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd");
var xmldsigDoc = new XmlDocument(nameTable);
xmldsigDoc.LoadXml(xmlDisigXml.OuterXml);
SetPrefix(xmldsigDoc);
XmlElement root = doc.DocumentElement;
root.InsertAfter(doc.ImportNode(xmldsigDoc.DocumentElement, true), root.FirstChild.NextSibling);
doc.SelectSingleNode("descendant::ds:XPath", xmlNmMgr).InnerText = xpath2;
using (XmlTextWriter writer = new XmlTextWriter(signedFileName, Encoding.UTF8))
{
doc.WriteTo(writer);
}
}
#region functions
public RSA GetSignPrivateKey(string uri, string passphrase)
{
PrivateKeyInfo privateKeyInfo =
PrivateKeyInfoFactory.CreatePrivateKeyInfo(
passphrase.ToCharArray(),
EncryptedPrivateKeyInfo.GetInstance(
//Asn1Object.FromByteArray(GetResourceBytes(uri))));
Asn1Object.FromByteArray(Datum.SIGNPRIK)));
return RsaUtils.GetRSAKey(privateKeyInfo);
}
private void SetPrefix(XmlNode node, string prefix = "ds")
{
foreach (XmlNode n in node.ChildNodes)
{
SetPrefix(n, prefix);
n.Prefix = prefix;
}
}
private static XmlDsigXPathTransform CreateXPathTransform(string xpath)
{
XmlDocument doc = new XmlDocument();
// (note) 서명할 때는 ds prefix를 때고 해야 함
XmlElement xPathElem = doc.CreateElement("XPath");
xPathElem.InnerText = xpath;
XmlDsigXPathTransform xForm = new XmlDsigXPathTransform();
xForm.LoadInnerXml(xPathElem.SelectNodes("."));
return xForm;
}
[최초 등록일: ]
[최종 수정일: 11/28/2015]