2016-09-06 22 views
0

Microsoftディレクティブに従って署名付きXMLドキュメントを検証しようとしていますが、CheckSignatureは常にfalseを返します。私は.NET 4.5を使用しています。もともと私はC14変換を使用していませんでしたが動作しませんでした。これは.NET 4.5のソリューションとして提案されていましたが動作しません。空白を保持することは、署名と検証の両方に当てはまることに注意してください。XML検証に失敗しました.SignedXml.CheckSignatureは常にfalseを返します

コードスニペットでは、簡略化のためにエラーチェックコードを削除しました。 はい、同様の質問を確認しましたが、答えが見つかりませんでした。

証明書(.PFXと.CER)

署名と検証は、ファイル(ない店)に証明書を用いて行われます。PluralSight SelfCertの自己署名証明書を使用し

  • ツール
  • パスワードで保護されたエクスポート可能な秘密鍵を使用してデジタル署名のための個人用自己署名証明書を作成しました。私は、証明書をエクスポートするcertmgr.mscを使用し、私は
  • パブリックとプライベートの両方のキーが含まれてい署名証明書(.PFX)で保存されたcertmgr.msc
  • を使用して私の個人ストアに証明書を見ることができます秘密鍵がないので、公開鍵だけです。これが唯一のverifcationのためのものであり、これまでのところは良い.cerファイル

に保存された、証明書が良いです。個人ストアでは、証明書とキーアイコンの両方を使用して署名証明書を表示します。

私はこのコードを使用しています署名XML今すぐXMLドキュメント

署名:署名のコードは次のように呼ばれて

static void SignXML(XmlDocument xmlDoc, RSA Key) 
{ 
     SignedXml signedXml = new SignedXml(xmlDoc); 
     if (Properties.Settings.Default.UseC14Transform) 
     { 
      // http://stackoverflow.com/questions/13632630/signedxml-checksignature-fails-in-net-4-but-it-works-in-net-3-5-3-or-2 
      signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; 
     } 

     // Add the key to the SignedXml document. 
     signedXml.SigningKey = Key; 

     // Create a reference to be signed. 
     Reference reference = new Reference(); 
     reference.Uri = ""; 
     if (Properties.Settings.Default.UseC14Transform) 
     { 
      reference.AddTransform(new XmlDsigExcC14NTransform()); // required to match doc 
      XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); 
      reference.AddTransform(env); 
     } 
     else 
     { 
      // Add an enveloped transformation to the reference. 
      XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); 
      reference.AddTransform(env); 
     } 

     // Add the reference to the SignedXml object. 
     signedXml.AddReference(reference); 

     // Compute the signature. 
     signedXml.ComputeSignature(); 

     // Get the XML representation of the signature and save 
     // it to an XmlElement object. 
     XmlElement xmlDigitalSignature = signedXml.GetXml(); 

     // Append the element to the XML document. 
     xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); 
} 

:XML署名の

XmlDocument doc = new XmlDocument(); 
doc.PreserveWhitespace = true; 
using (StringWriter _writer = new StringWriter()) 
{ 
    XmlSerializer serializer = new XmlSerializer(typeof(Models.Protected), new Type[] { param1.GetType() }); 
    serializer.Serialize(_writer, param1); 
    doc.LoadXml(_writer.ToString()); 
} 
// get RSA key from certificate (.PFX file) 
X509Certificate2 cert = new X509Certificate2(certPrivateKeyFilePath, certFilePwd); 
RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PrivateKey; 
SignXML(doc, rsaKey); 
return Convert.ToBase64String(Encoding.UTF8.GetBytes(doc.OuterXml)); 

検証を

私の検証方法は、次のようになります。署名されているオブジェクトがあるModels.Protectedクラスです

Models.Protected mdl = null; 
try 
{ // The certificate is in a .CER file, only has PUBLIC key 
    X509Certificate2 cert = new X509Certificate2(certPubKeyFilePath); 
    XmlDocument xmlDoc = new XmlDocument(); 
    xmlDoc.PreserveWhitespace = true; 
     xmlDoc.LoadXml(DocEncoding.GetString(Convert.FromBase64String(b64String))); 
    if (VerifyXml(xmlDoc, cert) 
    { 
     XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature"); 
     xmlDoc.DocumentElement.RemoveChild(nodeList[0]); 
     XmlSerializer _serializer = new XmlSerializer(typeof(Models.Protected), new Type[] { typeof(Models.Protected) }); 
     using (StringReader _reader = new StringReader(_safeXML)) 
       { 
        _safe = (Models.Protected)_serializer.Deserialize(_reader); 
       } 
    } 
} 
catch { /* something here */ } 

    return _safe; 
} 

その他

:順番にある

static Boolean VerifyXml(XmlDocument Doc, X509Certificate2 cert) 
{ 
    RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PublicKey.Key; 
    SignedXml signedXml = new SignedXml(Doc); 
    XmlNodeList nodeList = Doc.GetElementsByTagName("Signature"); 
    signedXml.LoadXml((XmlElement)nodeList[0]); 
    return signedXml.CheckSignature(rsaKey); 
} 

は次のように呼び出されましたシリアライズ可能。問題がそこにないように、それが正しくシリアル化されることを確認しました。

署名プロセスでは、期待されるXML署名付きの有効なXLファイルが生成され、これが次にBase64文字列に変換されます。

検証プロセスでは、生成されたものと同じ検証済みのBase64文字列が読み込まれます。デコード時に読み取られた同じB64文字列は、署名が完了したときに生成されたものとまったく同じ署名付きXML文書を生成します。

生成された署名付きXMLのMD5ハッシュは、検証前に取得された署名付きXMLのMD5ハッシュと同じです。したがって、彼らは絶対的に平等であり、その署名も同様です。

したがって、コンテンツが同一であり、証明書が正しく生成されていても、CheckSignatureがfalseを返すのは私の理解を超えています(.PFXと.CER)。例外はどこにもスローされず、単にfalseを返します。

私が間違っていることを誰でも見分けることができます

+1

私はちょうど唯一の修正が(固定)RSAParametersからRSAオブジェクトを構築し、固定入力文字列を使用していて、うまくいきました。排他的なc14nとデフォルトの両方を使用しています。だからあなたは本当に両方の側で同じ証明書を使用していることを確認したいことがあります。たとえば、RSAオブジェクトを取得し、ExportParameters(false)を呼び出してModulus値を出力します。 (ここでは多くのクリーンアップが適用されるかもしれませんが、私のテストではコードが機能してデータの問題が示唆されています)。それに失敗した場合は、シリアライザからサンプル入力文字列を与えてください。 – bartonjs

+0

@bartonjs私は気になるよ!私はあなたが示唆したようにして、法は同じではありませんでした!私はストア内の証明書から.CERを生成したので不思議です。しかし、私がしなかったのは、.NET 3.5のSelfCert PluralSightユーティリティ(何かがあるかどうかわからない)から、ストアに証明書を保存するのではなく、保存したPFXファイルを手動でインストールするそれは店で。それから私は店に行って輸出した。問題はそのように解決されました。これで、正しく検証されます。 –

+1

私は助けることができてうれしい:) – bartonjs

答えて

0

@bartonjsの偉大なヒントのおかげで、私はサインにあるモジュラスを検証し、証明書が同じではないことを確認できました。私が言及したように、PluralSightフリーのSelfCert GUIは、問題が発生したときと新しい(固定された)状況の両方で使用されました。

検証に使用された.CERファイルが格納された証明書から生成されたにもかかわらず、証明書に問題があるとコードに変更はありませんでした。

違いがありました。 SelfCert.exeにストアで証明書をインストールさせると、検証方法が失敗します。一方、.PFXファイルを生成した後ででない場合は、のGUIで「保存」ボタンを使用しますが、生成された.PFXファイルを使用して、証明書を秘密鍵で手動でインストールし、格納された証明書を.CERファイルとしてエクスポートします。モジュラスは同じで、サイン/ベリファイのプロセスは問題なく円滑に進みます。

関連する問題