2012-05-01 42 views
25

Tôi cần gửi tệp XML đã ký cho cơ quan chính phủ ở Braxin. Vấn đề là rằng tiêu hóa tính bằng mã Java của tôi (sử dụng Java XML Digital Signature API là khác nhau từ một trong những tạo ra với một công cụ như XMLSECGiá trị thông báo sai cho chữ ký xml bằng cách sử dụng Java XML Digital Signature API

Dưới đây là đoạn code tôi sử dụng để tạo ra một chữ ký XML cho một số nút 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); 

    } 

Nếu tôi cố gắng để xác nhận XML được tạo ra với xmlsec, tôi nhận được lỗi sau:

$ 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 

Nhưng nếu tôi cố gắng đăng ký các tập tin rất giống nhau (consult.xml) với xmlsec (bằng cách sử dụng khóa bí mật tương tự), lỗi đó xảy ra đi:

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

Sự khác biệt giữa consult.xml và doc-signed.xml (tạo ra bởi xmlsec) là nội dung của các thẻ SignatureValue và DigestValue:

consulta.xml:

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

doc-signed.xml:

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

Tôi sẽ không đăng phần còn lại của tệp vì chúng bằng nhau và sẽ làm cho bài đăng này thậm chí còn tiết lộ hơn nữa.

Từ những gì tôi có thể thu thập, ứng dụng web nhận tệp XML này là ứng dụng .NET và nó tính toán thông báo chữ ký khác với mã Java của tôi (giống như xmlsec). Bất kỳ ý tưởng?

+0

Xin lỗi, nhưng bạn có chắc chắn thuật toán băm thông báo là SHA1 không? Nó có thể là cái gì khác và chữ ký vẫn có thể là RSA_SHA1 (khi tôi đọc mã của bạn). – esej

+0

Đó là những gì tôi đang nói với Java API để làm. Một điều mà tôi nhận thấy là nếu tôi lưu tài liệu xmls vào một tệp, hãy đọc tệp đó và ký tên vào những gì tôi đọc, thông báo được tính toán chính xác. Vì vậy, tôi nghĩ có lẽ khoảng trắng được xem xét bằng cách nào đó trên cả Java hoặc bên XMLSEC. Điều đó sẽ giải quyết được vấn đề của tôi nếu tôi chỉ cần ký xml một lần; vấn đề là tôi cần phải làm ít nhất hai lần ... – Andre

+8

Bạn đã cheched '\ n'? –

Trả lời

1

Nếu nó không phải là quá muộn để trả lời:

Bạn tạo 2 Transforms trong mã (envelopedTransform và c14NTransform), nhưng không sử dụng chúng.

Bạn tạo tham chiếu bằng một Transform.ENVELOPED mới. http://www.w3.org/TR/2001/REC-xml-c14n-20010315 (C14N) biến đổi không được áp dụng.

Bây giờ, tôi không biết chắc chắn về tiêu chuẩn bảo mật XML cho biết hành vi phải như thế nào trong trường hợp này. Có lẽ các công cụ khác cũng tự động áp dụng biến đổi C14N.

Tôi biết chắc chắn nếu bạn KHÔNG chỉ định bất kỳ biến đổi JDK nào sẽ áp dụng ít nhất biến đổi C14N.

Về cơ bản, thay đổi fac.newReference ("", ...) và chuyển transformList vào nó thay vì Collections.singletonList().

0

Lý tưởng nhất là phần tử DigestValue chứa giá trị phân tích được mã hóa base64 thực tế trong API chữ ký XML Java. Bạn có thể vui lòng xác minh giá trị thông báo của bạn được tạo từ XMLSec cũng được mã hóa base64 hay không.

Các vấn đề liên quan