2012-05-01 3 views
25

Мне нужно отправить подписанный XML-файл в правительственное агентство в Бразилии. Проблема заключается в том, что гидролизат вычисляется моим Java кода (с помощью Java XML Digital Signature API отличается от сигнала с помощью другого инструмента, как XMLSECНеверное значение дайджест для подписи xml с использованием Java Digital Signature API

Вот код, я использую для создания 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); 

    } 

Если я пытаюсь проверить сгенерированный XML с xmlsec, я получаю следующее сообщение об ошибке:

$ 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 (используя один и тот же секретный ключ), эта ошибка расстояние:

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

Различия между consult.xml и док-signed.xml (генерируемой xmlsec) являются содержимое тегов SignatureValue и DigestValue:

consulta.xml:

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

док-signed.xml:

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

Я не буду размещать остальные либо файла, так как они равны и сделает этот пост еще более подробным.

Из того, что я могу собрать, веб-приложение, которое получает этот XML-файл, является .NET-приложением, и оно вычисляет другой дайджест подписи, который мой код Java (как и xmlsec). Есть идеи?

+0

Извините, но вы уверены, что алгоритм алгоритма дайджеста SHA1? Это может быть что-то другое, и подпись может быть RSA_SHA1 (поскольку я читаю ваш код). – esej

+0

Вот что я говорю API Java. Одна вещь, которую я заметил, заключается в том, что если я сохраню документ xmls в файле, прочитаю этот файл и подпишу, что я прочитал, дайджест рассчитан правильно. Поэтому я думаю, что пробелы каким-то образом рассматриваются как на Java, так и на стороне XMLSEC. Это решит мою проблему, если мне нужно будет подписать xml только один раз; проблема в том, что мне нужно сделать это хотя бы дважды ... – Andre

+8

Вы пробрали '\ n'? –

ответ

1

Если это не слишком поздно, чтобы ответить:

Вы создаете 2 трансформаций в коде (envelopedTransform и c14NTransform), но не использовать их.

Вы создаете ссылку с помощью одного нового Transform.ENVELOPED. Преобразование http://www.w3.org/TR/2001/REC-xml-c14n-20010315 (C14N) не применяется.

Теперь я не знаю точно, что стандарт безопасности XML говорит о том, что поведение должно быть в этом случае. Возможно, другие инструменты автоматически применяют преобразование C14N.

Я точно знаю, если вы НЕ укажете какое-либо преобразование. JDK будет применять хотя бы преобразование C14N.

В основном измените, что fac.newReference ("", ...) и передайте transformList в него вместо Collections.singletonList().

0

В идеале элемент DigestValue содержит фактическое значение дайджест-кодировки base64 в API подписи Java XML. Не могли бы вы подтвердить, что ваше значение дайджеста, созданное из XMLSec, также закодировано в base64.

 Смежные вопросы

  • Нет связанных вопросов^_^