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?
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
Đó 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
Bạn đã cheched '\ n'? –