2012-05-01 34 views
25

ブラジルの政府機関に署名したXMLファイルを送信する必要があります。 。問題は私のJavaコードによって計算されたダイジェストは、(Java XML Digital Signature APIを使用してXMLSECのような他のツールで生成されたものとは異なるということであるJava XMLデジタル署名APIを使用したxml署名のダイジェスト値が正しくない

ここで私はいくつかのXMLノードのXML署名を生成するために使用するコードです:

private synchronized void sign(XmlObject obj) throws Exception { 
     initKeystore(); 
     XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 
     List<Transform> transformList = new ArrayList<Transform>(); 
     Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); 
     Transform c14NTransform = fac.newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", 
       (TransformParameterSpec) null); 
     transformList.add(envelopedTransform); 
     transformList.add(c14NTransform); 
     Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), 
       Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, 
       null); 
     SignedInfo si = fac.newSignedInfo(
       fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), 
       fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); 
     KeyStore ks = KeyStore.getInstance("PKCS12"); 
     ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), 
       System.getProperty("javax.net.ssl.keyStorePassword").toCharArray()); 
     KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("entry", 
       new KeyStore.PasswordProtection(System.getProperty("javax.net.ssl.keyStorePassword").toCharArray())); 

     X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); 

     // Create the KeyInfo containing the X509Data. 
     KeyInfoFactory kif = fac.getKeyInfoFactory(); 
     X509Data xd = kif.newX509Data(Collections.singletonList(cert)); 
     KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 
     // Instantiate the document to be signed. 

     Element el = (Element) obj.getDomNode().getFirstChild(); 
     String id = el.getAttribute("Id"); 

     DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), el); 
     // Create the XMLSignature, but don't sign it yet. 
     XMLSignature signature = fac.newXMLSignature(si, ki); 
     // Marshal, generate, and sign the enveloped signature. 
     signature.sign(dsc); 

    } 
同じ秘密鍵を使用して

$ xmlsec1 --verify consulta.xml 
func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=229:obj=sha1:subj=unknown:error=12:invalid data:data and digest do not match 
FAIL 

しかし、私は非常に同じファイル(consult.xml)に署名しようとした場合xmlsecと(:

私はxmlsecで生成されたXMLを検証しようとすると、私は次のエラーを取得します)、そのエラーは離れ:

consulta.xml:

<DigestValue>Ajn+tfX7JQc0HPNJ8KbTy7Q2f8I=</DigestValue> 
... 
<SignatureValue>Q1Ys0Rtj8yL2SA2NaQWQPtmNuHKK8q2anPiyLWlH7mOIjwOs0GEcD0WLUM/BZU0Q 
T0kSbDTuJeTR2Ec9wu+hqXXbJ76FpX9/IyHrdyx2hLg0VhB5RRCdyBEuGlmnsFDf 
XCyBotP+ZyEzolbTCN9TjCUnXNDWtFP1YapMxAIA0sth0lTpYgGJd8CSvFlHdFj+ 
ourf8ZGiDmSTkVkKnqDsj8O0ZLmbZfJpH2CBKicX+Ct7MUz2sqVli4XAHs6WXX+E 
HJpbOKthS3WCcpG3Kw4K50yIYGTkTbWCYFxOVsMfiVy4W/Qz15Vxb8chD8LM58Ep 
m/szmvnTAESxv/piDr7hyw==</SignatureValue> 

xmlsec1 --sign --output doc-signed.xml --privkey-pem cert.pem consulta.xml 

consult.xml及び(xmlsecによって生成された)DOC-signed.xml違いはSignatureValueとDigestValueタグの内容は

DOC-signed.xml:

<DigestValue>w6xElXJrZw3G86OsNkWav+pcKJo=</DigestValue> 
... 
<SignatureValue>YmUsnlnAY9uLhlfVBLhB8K8ArxMOkOKZJoQ6zgz55ggU6vJCO9+HWJCKQJp6Rvn/w5PCAFY0KJRb 
r6/WhHML0Z+Q6TSuIL8OTvJ3iPoROAK6uy07YAflKOUklqk4uxgfMkR+hWMCyfITJVCVZo/MXmPy 
g7YwmztoSlGH+p6+ND5n2u47Y2k6SpIvw3CUxwAVQkD0Hsj3G58cbUbrFCoyPVGOe4zJ9c1HPsMW 
KzBEFe3QETzPJ8I1B7EEVi5oDvzXE2rMTH4K7zvNGnXpBNGwnSjEOticlqKVP5wyUD7CPwgF1Wgy 
Z0njvlaW3K8YmAY8fc70v/+wSO6Fu+0zj18Xeg==</SignatureValue> 

彼らは同じだから、私はどちらかのファイルの残りの部分を投稿しないだろうし、この投稿をもっと冗長にするでしょう。

このXMLファイルを受け取るWebアプリケーションは.NETアプリケーションで、Javaコード(xmlsecとよく似ています)とは異なる署名ダイジェストを計算します。何か案は?

+0

申し訳ありませんが、ダイジェストハッシュアルゴリズムはSHA1ですか?それは他のものでも構いませんし、署名はRSA_SHA1(あなたのコードを読んでいるので)でもかまいません。 – esej

+0

それは私がJava APIにすることです。私が気づいたことの一つは、xmlsドキュメントをファイルに保存し、そのファイルを読み込んで私が読んだものに署名すると、ダイジェストが正しく計算されるということです。ですから、空白が何らかの形でJavaまたはXMLSEC側で検討されている可能性があります。 xmlに一度だけ署名する必要があれば、それは私の問題を解決するでしょう。問題は私が少なくとも2回それをする必要があるということです... – Andre

+8

あなたは '\ n'を騙しましたか? –

答えて

1

それは答えることは手遅れではない場合:

あなたは、コード内で2つの変換(envelopedTransformとc14NTransform)を作成し、それらを使用しないでください。

新しい1つのTransform.ENVELOPEDを使用して参照を作成します。 http://www.w3.org/TR/2001/REC-xml-c14n-20010315(C14N)変換は適用されません。

ここでは、XMLセキュリティー標準が、この場合の動作をどういうものにするかについてはわかりません。多分、他のツールもC14N変換を自動的に適用します。

変換を指定しない場合、JDKは少なくともC14N変換を適用することが確実です。

基本的にfac.newReference( ""、...)を変更し、Collections.singletonList()ではなくtransformListを渡します。

0

理想的には、DigestValue要素には、Java XML署名APIの実際のbase64エンコードされたダイジェスト値が含まれています。 XMLSecから作成されたダイジェスト値もbase64でエンコードされていることを確認してください。

関連する問題