PKCS#12形式ファイルを使ってXML文書に署名付与したり、署名検証したり
PKCS#12(拡張子.p12のファイル)を使ってXML文書にXML署名(Enveloped署名)を行うのと署名検証するプログラムをC#で作ってみた。
- 基本、SignedXmlクラスに載っているコードを使った。(2つあるけど、上の方は署名の公開鍵を埋め込まない。下の方はRSAKeyValueを埋め込んでいる)
でも、このコードは、証明書(RSA)を生成してそれをKeyInfo要素にRSAKeyValue要素が設定する。
PKCS#12形式ファイルを読み込んで使いたいし、x509Certificate要素を入れたい。 - PKCS#12形式ファイルのprivateKeyを取り出すには、手順がある。
- PKCS#12ファイルを、new X509Certificate2(<filename>, <password>, X509KeyStorageFlags.Exportable);で読み込む。
- そのx509からprivateKeyを取り出すには、(RSACryptoServiceProvider)x509.PrivateKey;とやる。
この使おうとするとsignedXml.ComputeSignature()で「無効なアルゴリズムが指定されました」例外になってしまう・・・。PersistKeyInCspがtrueの所為? - 上記の例外を回避するには、別のRSACryptoServiceProvider()インスタンスに対して、ImportParameters(privateKey.ExportParameters(true));とやって、先ほどのprivateKeyを食わせる。するとPersistKeyInCspがfalseになっているね。
- KeyInfo要素にRSAKeyValue要素が入るのは、keyInfo.AddClause(new RSAKeyValue((RSA)Key));とやっている。
x509Certificate要素を入れるのには、keyInfo.AddClause(new KeyInfoX509Data(x509));とやる。
●引数:
- 第1引数:PKCS#12ファイル
- 第2引数:PKCS#12ファイルのパスワード
- 第3引数:署名を付与するXML文書
- 第4引数:署名を付与する要素(id属性の値を設定)
- 第5引数:出力する署名済XML文書
C:\test>VerfySignedXML.exe my-identity.p12 test test.xml xxxx test_signed.xml
The XML signature is valid.
●署名対象のXML : test.xml <?xml version="1.0" encoding="utf-8" ?> <root> <creditcard id="xxxx"> <number>19834209</number> <expiry>02/02/2002</expiry> </creditcard> </root>
●署名付与したXML : test_signed.xml <?xml version="1.0" encoding="utf-8"?> <root> <creditcard id="xxxx"> <number>19834209</number> <expiry>02/02/2002</expiry> </creditcard> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#xxxx"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>7WFHBFyOfyEEGK6n7OHvdA6K345HSlAVwPFaEWgXcX0=</DigestValue></Reference></SignedInfo><SignatureValue>JWPhDDxFQalUmtWPdd8o55To3p5RI7TJvnXz79H2tb60J4B1lg4TeTvTOtHZuiJJpHZMeNyuARtwNRX+etDr9j4UmXdUJ/CXvxJFXajoYXRwTGYK6i/RF0QDeoOexSFYrK+JZeHrUV6T7UMU6O5ZxrmuU+c7U7Ki0dlHypdjQac=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIClTCCAf4CCQCBK5YXcZkuqjANBgkqhkiG9w0BAQsFADCBjjELMAkGA1UEBhMCSlAxETAPBgNVBAgMCEtBTkFHQVdBMREwDwYDVQQHDAhZT0tPU1VLQTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlLT1RBVFVJTlUxIjAgBgkqhkiG9w0BCQEWE2tvdGF0dWludUBuaWZ0eS5jb20wHhcNMTcxMjA5MTE1NTQ3WhcNMjcxMjA3MTE1NTQ3WjCBjjELMAkGA1UEBhMCSlAxETAPBgNVBAgMCEtBTkFHQVdBMREwDwYDVQQHDAhZT0tPU1VLQTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlLT1RBVFVJTlUxIjAgBgkqhkiG9w0BCQEWE2tvdGF0dWludUBuaWZ0eS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMPnNgYbe5x2xJyEshyH768ZU8Un5e5j5uKsihiTOya9wAdxNJeWINB21zXe+mjKxnOsmATPdGZ0DH82xqz+2mX//JKqwDMsG8nMacUI4BiCvYGvlTyxWkRQw3LKU2ufQQ+GYboypwQE51X3S+rRDLGoLuG0BtRooAvah1adJfhdAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAClBDgTCsbe19+CYomJC0PciFw/tvk6/TiC6VSNuQmFg61KrTaU4XFmj/u8qbD8ESyXaJKavcZmjWhKk6F6JSx9YYBz0b1dXz/9l0po6AwUooDk3yp5NtRGiErAcM6MCZ5LPM9+255hMa3fxX26Y7xpPxH84jv6j2fiYcsdYknaQ=</X509Certificate></X509Data></KeyInfo></Signature></root>
using System; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.Xml; public class VerifySignedXML { // 引数 // 1:PKCS12ファイル // 2:パスワード // 3:署名前XMLファイル(入力) // 4:署名付与対象(ID属性の値) // 5:署名済XMLファイル(出力) public static void Main(String[] args) { if (args.Length != 5) { return; } sign(args[0], args[1], args[2], args[3], args[4]); verfy(args[4]); } public static void sign(String filename, string password, string xmlFilename, string id, string signedXmlFilename) { try { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.PreserveWhitespace = true; xmlDoc.Load(xmlFilename); XmlNodeList list = xmlDoc.SelectNodes(string.Format(@"//*[@id='{0}']", id)); if (list.Count == 0) { return; } X509Certificate2 x509 = new X509Certificate2(filename, password, X509KeyStorageFlags.Exportable); SignXml(xmlDoc, x509, id); xmlDoc.Save(signedXmlFilename); } catch (Exception e) { Console.WriteLine(e.Message); } } public static void SignXml(XmlDocument xmlDoc, X509Certificate2 x509, string uri) { if (xmlDoc == null) { throw new ArgumentException("xmlDoc"); } if (x509 == null) { throw new ArgumentException("x509"); } SignedXml signedXml = new SignedXml(xmlDoc); RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)x509.PrivateKey; RSACryptoServiceProvider privateKey1 = new RSACryptoServiceProvider(); privateKey1.ImportParameters(privateKey.ExportParameters(true)); signedXml.SigningKey = privateKey1; Reference reference = new Reference(); reference.Uri = "#" + uri; XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); signedXml.AddReference(reference); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(x509)); signedXml.KeyInfo = keyInfo; signedXml.ComputeSignature(); XmlElement xmlDigitalSignature = signedXml.GetXml(); xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); } public static void verfy(string signedXmlFilename) { try { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.PreserveWhitespace = true; xmlDoc.Load(signedXmlFilename); bool result = VerifyXml(xmlDoc); if (result) { Console.WriteLine("The XML signature is valid."); } else { Console.WriteLine("The XML signature is not valid."); } } catch (Exception e) { Console.WriteLine(e.Message); } } public static Boolean VerifyXml(XmlDocument Doc) { SignedXml signedXml = new SignedXml(Doc); XmlNodeList nodeList = Doc.GetElementsByTagName("Signature"); if (nodeList.Count <= 0) { throw new CryptographicException("Verification failed: No Signature was found in the document."); } if (nodeList.Count >= 2) { throw new CryptographicException("Verification failed: More that one signature was found for the document."); } signedXml.LoadXml((XmlElement)nodeList[0]); return signedXml.CheckSignature(); } }
« 株:買い約定(三菱商事、三井物産) | トップページ | 今週届いた本 »
コメント