前提
C#で内部detached形式、XAdES-BES形式の署名を行うシステムを作成しています。
署名をRSA SHA256で行いたいのですが、署名の際に、
System.Security.Cryptography.CryptographicException
無効なアルゴリズムが指定されました。
と、例外が発生してしまいます。
実現したいこと
指定した証明書から取得した秘密キーでの署名をRSA SHA256で行う。
発生している問題・エラーメッセージ
無効なアルゴリズムが指定されました。
該当のソースコード
C#
1using System; 2using System.Collections.Generic; 3using System.Xml; 4using System.Security.Cryptography; 5using System.Security.Cryptography.Xml; 6using System.Security.Cryptography.X509Certificates; 7 8namespace XmlSignTest 9{ 10 public class MySignedXml : SignedXml 11 { 12 private readonly List<DataObject> dataObjects = new List<DataObject>(); 13 14 public MySignedXml(XmlDocument document):base(document){} 15 16 public override XmlElement GetIdElement(XmlDocument document, string idValue) 17 { 18 if (string.IsNullOrEmpty(idValue)) 19 { 20 return null; 21 } 22 23 XmlElement elem = base.GetIdElement(document, idValue); 24 if (null != elem) 25 { 26 return elem; 27 } 28 29 foreach (DataObject data in dataObjects) 30 { 31 elem = findNodeWithAttributeValueIn(data.Data, "Id", idValue); 32 if (null != elem) 33 { 34 return elem; 35 } 36 } 37 38 if (base.KeyInfo != null) 39 { 40 elem = findNodeWithAttributeValueIn(base.KeyInfo.GetXml().SelectNodes("."), "Id", idValue); 41 if (null != elem) 42 { 43 return elem; 44 } 45 } 46 47 return null; 48 } 49 50 public new void AddObject(DataObject data) 51 { 52 base.AddObject(data); 53 dataObjects.Add(data); 54 } 55 56 public XmlElement findNodeWithAttributeValueIn(XmlNodeList nodeList, string attributeName, string value) 57 { 58 if (nodeList.Count == 0) 59 { 60 return null; 61 } 62 63 foreach (XmlNode node in nodeList) 64 { 65 XmlElement nodeWithSameId = findNodeWithAttributeValueIn(node, attributeName, value); 66 if (nodeWithSameId != null) 67 { 68 return nodeWithSameId; 69 } 70 } 71 return null; 72 } 73 74 private XmlElement findNodeWithAttributeValueIn(XmlNode node, string attributeName, string value) 75 { 76 string attributeValueInNode = getAttributeValueInNodeOrNull(node, attributeName); 77 if ((attributeValueInNode != null) && (attributeValueInNode.Equals(value))) 78 { 79 return (XmlElement)node; 80 } 81 return findNodeWithAttributeValueIn(node.ChildNodes, attributeName, value); 82 } 83 84 private string getAttributeValueInNodeOrNull(XmlNode node, string attributeName) 85 { 86 if (node.Attributes != null) 87 { 88 XmlAttribute attribute = node.Attributes[attributeName]; 89 if (attribute != null) 90 { 91 return attribute.Value; 92 } 93 } 94 return null; 95 } 96 } 97 98 class Program 99 { 100 static void Main(string[] args) 101 { 102 XmlDocument doc = new XmlDocument(); 103 104 doc.PreserveWhitespace = true; 105 doc.Load("test.xml"); 106 107 MySignedXml sxml = new MySignedXml(doc); 108 109 Signature sig = sxml.Signature; 110 sig.Id = "TestSign"; 111 112 sxml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; 113 sxml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url; 114 115 Reference refer = new Reference(); 116 refer.Uri = "#TestDocument"; 117 refer.DigestMethod = SignedXml.XmlDsigSHA256Url; 118 119 Reference refer2 = new Reference(); 120 refer2.Uri = "#SignedProperties01"; 121 refer2.Type = "http://uri.etsi.org/01903#SignedProperties"; 122 refer2.AddTransform(new XmlDsigC14NTransform()); 123 refer2.DigestMethod = SignedXml.XmlDsigSHA256Url; 124 125 Reference refer3 = new Reference(); 126 refer3.Uri = "#KeyInfo01"; 127 refer3.AddTransform(new XmlDsigC14NTransform()); 128 refer3.DigestMethod = SignedXml.XmlDsigSHA256Url; 129 130 X509Certificate2 cert = null; 131 X509Store store = new X509Store(StoreName.My); 132 store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); 133 X509Certificate2Collection certCollection = store.Certificates; 134 X509Certificate2Collection foundCert = certCollection.Find(X509FindType.FindByIssuerName, "Issuer-Name", true); 135 cert = foundCert[0]; 136 store.Close(); 137 138 sxml.SigningKey = cert.PrivateKey; 139 140 KeyInfo key = new KeyInfo(); 141 key.Id = "KeyInfo01"; 142 key.AddClause(new KeyInfoX509Data(cert)); 143 sxml.KeyInfo = key; 144 145 XmlElement qpElem = doc.CreateElement("xa132", "QualifyingProperties", "http://uri.etsi.org/09103/v1.3.2#"); 146 qpElem.SetAttribute("Target", "#TestSign"); 147 XmlElement spElem = doc.CreateElement("xa132", "SignedProperties", "http://uri.etsi.org/09103/v1.3.2#"); 148 spElem.SetAttribute("Id", "SignedProperties01"); 149 XmlElement sspElem = doc.CreateElement("xa132", "SignedSignatureProperties", "http://uri.etsi.org/09103/v1.3.2#"); 150 151 spElem.AppendChild(sspElem); 152 qpElem.AppendChild(spElem); 153 154 DataObject obj = new DataObject(); 155 obj.Data = qpElem.SelectNodes("."); 156 sxml.AddObject(obj); 157 158 sxml.AddReference(refer); 159 sxml.AddReference(refer2); 160 sxml.AddReference(refer3); 161 162 sxml.ComputeSignature(); // ここで例外発生 163 164 XmlElement xmlDigitalSignature = sxml.GetXml(); 165 166 XmlNode node = doc.SelectSingleNode("Document/Test/TestSign"); 167 node.AppendChild(doc.ImportNode(xmlDigitalSignature, true)); 168 169 doc.Save("signed.xml"); 170 171 doc.Load("signed.xml"); 172 sxml = new MySignedXml(doc); 173 XmlNodeList nodelist = doc.GetElementsByTagName("Signature"); 174 sxml.LoadXml((XmlElement)nodelist[0]); 175 bool b = sxml.CheckSignature(cert, true); 176 if (b) 177 { 178 System.Windows.Forms.MessageBox.Show("valid."); 179 } 180 else 181 { 182 System.Windows.Forms.MessageBox.Show("not valid."); 183 } 184 185 } 186 } 187} 188
試したこと
-
sxml.SignedInfo.SignatureMethod の値を SignedXml.XmlDsigRSASHA1Url にすると、例外が発生せずにPIN入力のダイアログが表示され、PIN入力後に署名付きのXMLファイルが生成されましたが、<SignatureMethod>のAlgorithm属性の値が "http://www.w3.org/2000/09/xmldsig#rsa-sha1" になってしまいました。
-
sxml.SigningKeyの取得方法を以下のようにしたところ、<SignatureMethod>のAlgorithm属性の値は"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" になりましたが、PIN入力のダイアログが表示されませんでした。PINを設定している箇所はどこにもないので、この署名ではダメだと思われます。
C#
1RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey; 2CspParameters csp = new CspParameters(); 3csp.ProviderName = null; 4csp.ProviderType = 24; 5csp.KeyNumber = (int)rsa.CspKeyContainerInfo.KeyNumber; 6csp.KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName; 7RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider(csp); 8sxml.SigningKey = rsa2;
どちらもCheckSignature()の結果はfalseでした。
PINを設定してかつ、<SignatureMethod>のAlgorithm属性の値を"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" にしたいです。
2022/12/22 追記
取得した証明書の PrivateKey.SignatureAlgorithm プロパティの値を確認したところ、"http://www.w3.org/2000/09/xmldsig#rsa-sha1" となっていました。何か関係があるのでしょうか?
補足情報(FW/ツールのバージョンなど)
署名するXMLファイルは以下のようになっています。
<TestSign>と</TestSign>の間に署名が入ります。
XML
1<?xml version="1.0" encoding="utf-8"?> 2<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Document" xsi:noNamespaceSchemaLocation="EP.xsd"> 3 <Test> 4 <TestDocument id="TestDocument">testtesttest</TestDocument> 5 <TestSign> 6 </TestSign> 7 </Test> 8</Document>
OS Windows7 Professional SP1
開発ツール Visual Studio 2017
ターゲットフレームワーク .NET Framework 4.8
あなたの回答
tips
プレビュー