XML署名の手動検証
-
08-10-2019 - |
質問
手動参照検証(参照されるすべての要素 - > sha1-> base64->消化量コンテンツと同じかどうかを確認)を正常に実行できますが、署名の値の検証に失敗します。これがCanonicalizeとHashのSignedInfoです。
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#element-1-1291739860070-11803898">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>d2cIarD4atw3HFADamfO9YTKkKs=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#timestamp">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>YR/fZlwJdw+KbyP24UYiyDv8/Dc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
タグ間のすべてのスペースを削除する(そして、単一の行で要素全体を取得する)、私はこのSHA1ダイジェストを取得します(base64):
6l26ibh7il/yrcqw6eefv/vqavo =
今、私はSignatureValueコンテンツの復号化の後に同じダイジェストを見つけることを期待していますが、私は別のものを取得し、 より長いです 価値:
mcewcqyfkw4dahofaqu3m24vwkg02yu6jleh+u6r4n8ig =
これがデキタプトのためのいくつかのJavaコードです:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new File(inputFilePath));
NodeList nl = doc.getElementsByTagName("ds:SignatureValue");
if (nl.getLength() == 0) {
throw new Exception("Cannot find SignatureValue element");
}
String signature = "OZg96GMrGh0cEwbpHwv3KDhFtFcnzPxbwp9Xv0pgw8Mr9+NIjRlg/G1OyIZ3SdcOYqqzF4/TVLDi5VclwnjBAFl3SEdkyUbbjXVAGkSsxPQcC4un9UYcecESETlAgV8UrHV3zTrjAWQvDg/YBKveoH90FIhfAthslqeFu3h9U20=";
X509Certificate cert = X509Certificate.getInstance(new FileInputStream(<a file path>));
PublicKey pubkey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA","SunJCE");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
byte[] decodedSignature = Base64Coder.decode(signature);
cipher.update(decodedSignature);
byte[] sha1 = cipher.doFinal();
System.out.println(Base64Coder.encode(sha1));
私を非常に混乱させるのは、2つのダイジェストのサイズが異なることですが、もちろん2つの計算からまったく同じ値を取得する必要があります。助言がありますか?ありがとうございました。
解決
MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH+u6R4N8Ig=
base64は、derエンコードされたasn.1構造のためのエンコードです:a SEQUENCE
最初のanを含む AlgorithmIdentifier
(これはSHA-1であり、SHA-1が何も受け入れないためパラメーターはないと述べています)、そして OCTET STRING
実際の20バイト値が含まれています。 16進数では、値は次のとおりです。 dccdb8570286d36c94bba8e5107faee91e0df088
.
このASN.1構造は標準の一部です RSA署名 機構。 RSAを使用しています 復号化 非標準であるその構造にアクセスするため。あなたは実際に何かを手に入れることができて幸運です。 RSA暗号化 と RSA署名 2つの異なるアルゴリズムです。どちらも同じ種類のキーペアを食べ、「古いスタイル」(別名「PKCS#1 V1.5」)の署名と暗号化スキームが同様のパディングテクニックを使用していることがあります(同様ですが、同一ではありません。 RSAのJava実装が、復号化モードで使用された場合、署名パディングを窒息させなかったことはすでに少し驚くべきことです。
ともかく、 6l26iBH7il/yrCQW6eEfv/VqAVo=
20バイトの値でbase64をエンコードしています。これは、16進数では次のとおりです。 ea5dba8811fb8a5ff2ac2416e9e11fbff56a015a
. 。これは、タグ間ですべての空白を削除した後、上記のXML構造をハッシュすることで得られるものです。すべての空白を削除します いいえ 適切な標準化。実際、私の知る限り、白人はタグ内の属性間でのみ影響を受けますが、外部の空白は変更せずに保つ必要があります(ラインエンディング正規化[LF / CR+LFのもの]を除く)。
署名生成に使用された値( dccdb85...
)表示するXMLオブジェクトを使用して、主要なスペースを削除することで取得できます。明確にするには、XMLをファイルにコピーして貼り付けてから、各ラインの主要なスペース(0〜3スペース)を削除します。すべてのラインの終わりが単一のLF(0x0Aバイト)を使用し、最終lf(直後のLF)を削除することを確認します。 </ds:SignedInfo>
)。結果のファイルには長さ930バイトが必要であり、そのSHA-1ハッシュは予想されます dccdb85...
価値。
他のヒント
あなたの特定のXMLトークンを見ると、私はあなたにいくつかのことを伝えることができます。
標準化法を使用しています 排他的なXML Canonicalizationバージョン1.0. 。これは非常にです 重要 適切なダイジェスト値と署名を生成することを確認します。
参照ダイジェストを計算するために、また標準化のために同じ標準化方法を使用しています signedinfo署名を作成する前に。
排他的なXML Canonicalizaitonバージョン1.0の仕様はW3Cによって生成され、それぞれで見つけることができます W3Cの推奨. 。値を手動で計算している場合は、標準化が正しくなるのが難しいことであり、これを正しく行うことが非常に重要であるため、仕様に正確に適合していることを確認してください。
XML署名検証プロセスを説明する広範な記事を書いたばかりです。記事はにあります 私のブログ. 。 XML署名には多くの複雑さがあるため、プロセスを私の答えよりもはるかに詳細に説明しています。また、一般的な仕様とRFCへのリンクも含まれています。