2016-03-31 175 views
1

我有一個簽名的數字簽名XML文件和公共證書,我想驗證簽名。響應xml的原始內容返回false,但是當我修改xml時,它返回true。我的Java代碼如下: -Java中的XML簽名驗證失敗

import java.io.FileInputStream; 
import java.io.IOException; 
import java.security.GeneralSecurityException; 
import java.security.Security; 
import java.security.cert.CertificateFactory; 
import java.security.cert.X509Certificate; 
import javax.xml.crypto.dsig.XMLSignature; 
import javax.xml.crypto.dsig.XMLSignatureFactory; 
import javax.xml.crypto.dsig.dom.DOMValidateContext; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import org.bouncycastle.jce.provider.BouncyCastleProvider; 
import org.w3c.dom.Document; 
import org.w3c.dom.NodeList; 
public class SignatureVerifierOneFile { 
    public static void main(String[] args){  
     Security.addProvider(new BouncyCastleProvider());  
     //Signed xml path 
     String signedXmlPath = "C:/signedXML.xml";  
     SignatureVerifierOneFile signatureVerifier = new SignatureVerifierOneFile(); 
     boolean signatureStatus = 
signatureVerifier.verify(signedXmlPath,"C:/Cert.cer"); 
     System.out.println("xml signature validateionis " + signatureStatus); 

    } 
    public boolean verify(String signedXml,String publicKeyFile) { 

     boolean verificationResult = false; 

     try { 

      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
      dbf.setNamespaceAware(true); 
      DocumentBuilder builder = dbf.newDocumentBuilder(); 
      Document doc = builder.parse(signedXml); 
      NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); 
      if (nl.getLength() == 0) { 
       throw new IllegalArgumentException("Cannot find Signature element"); 
      } 

      XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

      DOMValidateContext valContext = new DOMValidateContext(getCertificateFromFile(publicKeyFile).getPublicKey(), nl.item(0)); 
      XMLSignature signature = fac.unmarshalXMLSignature(valContext); 

      verificationResult = signature.validate(valContext); 

     } catch (Exception e) { 
      System.out.println("Error while verifying digital siganature" + e.getMessage()); 
      e.printStackTrace(); 
     } 

     return verificationResult; 
    } 

    private X509Certificate getCertificateFromFile(String certificateFile) throws GeneralSecurityException, IOException { 
     FileInputStream fis = null; 
     try { 
      CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC"); 
      fis = new FileInputStream(certificateFile); 
      return (X509Certificate) certFactory.generateCertificate(fis); 
     } finally { 
      if (fis != null) { 
       fis.close(); 
      } 
     } 

    } 
} 

我原來的簽名XML是如下: -

<OTPResp resCode="25f341e7-8c72-47a6-b49b-46732e7b8494" status="1" ts="2016-03-31T10:54:07.575" txn="20160331052355192"><AadhaarResp>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxBZ2VudE90cFJlc3AgcmV0PSJ5IiB0cz0iMjAxNi0wMy0zMVQxMDo1NzoxMi41MzYrMDU6MzAiIGNvZGU9IjZkZjZhZTY1YzMwNjQzMmVhZTkyNzljYTgxZGNkNmJjIiB0eG49IjI1ZjM0MWU3LThjNzItNDdhNi1iNDliLTQ2NzMyZTdiODQ5NCIvPg==</AadhaarResp><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>vOND//Y2bsHBIkxkUfjH3d/CYC4=</DigestValue></Reference></SignedInfo><SignatureValue>HJG1vPQ4CSycCJ4B065faSeBaHGad9XYDUCOj9a/Fa/bWUUFYOpi9/jxVRCngSJACEIEVwUfcCKs9uUEr3DPcDiTB1UqM9BwUCVL28Tghn/HUSg53IQZziDrI3Ta2VyB7oHEoE/8cloArAbu44gDL/selJDD4ZtAsLAecO3NFiugMG3okV7hGcX50lIDm1on7ziFTxFfL1215gmcCfwJhF/zKI0GVBV6FcCDZxLeY7qMGp0Mj4EzicQm1LIZDHIfVskh97NrWi3MKBAv9dPGOevB3XaVw7dt9nct1VEirZaprM/dl5frCDTuwtmNlZN01dnBGHDCRi/+534mvN4oUQ==</SignatureValue></Signature></OTPResp> 

Mofidied XML這我能確認是如下

<OTPResp resCode="25f341e7-8c72-47a6-b49b-46732e7b8494" status="1" ts="2016-03-31T10:54:07.575" txn="20160331052355192"><AadhaarResp>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxBZ2VudE90cFJlc3AgcmV0PSJ5IiB0cz0iMjAxNi0wMy0zMVQxMDo1NzoxMi41MzYrMDU6MzAiIGNvZGU9IjZkZjZhZTY1YzMwNjQzMmVhZTkyNzljYTgxZGNkNmJjIiB0eG49IjI1ZjM0MWU3LThjNzItNDdhNi1iNDliLTQ2NzMyZTdiODQ5NCIvPg==</AadhaarResp><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
<SignedInfo> 
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> 
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> 
<Reference URI=""> 
<Transforms> 
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform> 
</Transforms> 
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> 
<DigestValue>vOND//Y2bsHBIkxkUfjH3d/CYC4=</DigestValue> 
</Reference> 
</SignedInfo> 
<SignatureValue> 
HJG1vPQ4CSycCJ4B065faSeBaHGad9XYDUCOj9a/Fa/bWUUFYOpi9/jxVRCngSJACEIEVwUfcCKs 
9uUEr3DPcDiTB1UqM9BwUCVL28Tghn/HUSg53IQZziDrI3Ta2VyB7oHEoE/8cloArAbu44gDL/se 
lJDD4ZtAsLAecO3NFiugMG3okV7hGcX50lIDm1on7ziFTxFfL1215gmcCfwJhF/zKI0GVBV6FcCD 
ZxLeY7qMGp0Mj4EzicQm1LIZDHIfVskh97NrWi3MKBAv9dPGOevB3XaVw7dt9nct1VEirZaprM/d 
l5frCDTuwtmNlZN01dnBGHDCRi/+534mvN4oUQ== 
</SignatureValue> 
</Signature></OTPResp> 

我無法弄清楚我是什麼做錯了? 在此先感謝。

回答

1

看看你的XML文檔,唯一對我來說很重要的區別是實際的​​3210內容。儘管它在Base64序列方面是相同的,但請注意,在您修改的XML中,它包含換行符。

通過XML DSIG規範來看,我們發現這樣的:http://www.w3.org/TR/xmldsig-core/#sec-SignatureValue

SignatureValue元素包含數字簽名的實際價值;它使用的base64 [MIME]

然後它引用的RFC 2045這裏的鏈接總是被編碼:http://www.ietf.org/rfc/rfc2045.txt

通過6.8節去,它指定了Base64編碼,它提到:

編碼後的輸出流必須用不超過 的行表示,每行不得超過76個字符。

而這正是您在修改過的XML中所做的。將XML轉換爲DOM,元素的文本內容與輸入文檔中的內容保持完全一致,包括換行符。我的猜測是,Java XML加密包使用的Base64解碼器嚴格遵守規範,並且未能完全解析原始XML文檔中的簽名。

我建議在方法verify中獲得XMLSignature之後,您可以嘗試調用getSignatureValue()。這應該給你一個XMLSignature.SignatureValue。嘗試從它獲取字節數組。如果它是空的,那麼儘快完成整個故障,上述可能是問題。

+1

@ G_H我同意你「編碼後的輸出流必須用不超過76個字符的行來表示」,實際上驗證源是正確的,問題出現在signedXML的讀取機制中,而在讀取signedXML時它正在刪除換行符字符。 – dpilwal