XML 签名验证在 java 中失败

XML signature validation fails in java

我有一个数字签名的 XML 文件和 Public 签名者证书,我想验证签名。响应 xml 的原始内容返回 false,但是当我修改 xml 时它 returns 为真。我的 java 代码如下:-

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>

我无法弄清楚我做错了什么? 提前致谢。

查看您的 XML 文档,对我来说唯一重要的区别是实际的 <SignatureValue> 内容。虽然它在 Base64 序列方面是相同的,但请注意,在您修改的 XML 中它包含换行符。

查看 XML DSIG 规范,我们发现:http://www.w3.org/TR/xmldsig-core/#sec-SignatureValue

The SignatureValue element contains the actual value of the digital signature; it is always encoded using base64 [MIME]

然后引用 RFC 2045。这是 link:http://www.ietf.org/rfc/rfc2045.txt

通过第 6.8 节,它指定了 Base64 编码,它提到:

The encoded output stream must be represented in lines of no more than 76 characters each.

这正是您在修改后的 XML 中所做的。将 XML 变成 DOM,元素的文本内容与输入文档中的内容完全相同,包括换行符。我的猜测是 Java XML 加密包使用的 Base64 解码器严格遵守规范,无法完全解析原始 XML 文档中的签名。

我建议在方法 verify 中获得你的 XMLSignature 之后,你尝试调用 getSignatureValue() 方法。这应该会给你一个 XMLSignature.SignatureValue。尝试从中获取字节数组。如果它是空的,过早切断获取 XMLSignature.SignatureValue 完全失败,以上可能是问题所在。