XML签名验证在Java中失败 - java

我有一个数字签名XML文件和签名者公共证书,我想验证签名。响应xml的原始内容返回false,但是当我修改xml时,它返回true。我的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();
            }
        }

    }
}

我原始的Signed 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

SignatureValue元素包含数字签名的实际值。它始终使用base64 [MIME]进行编码

然后,它引用RFC2045。这是链接:http://www.ietf.org/rfc/rfc2045.txt

通过第6.8节,该节指定了Base64编码,其中提到:

编码后的输出流必须不再以行表示
每个超过76个字符。

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

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

SOAPFaultException部署在Tomcat上时,但在GlassFish中工作正常 - java

朋友们,我一直在尝试很多,阅读了很多论坛,但无法理解为什么出现此问题。我使用契约优先方法创建了一个Jax-WS WebService。创建WSDL和XSD,然后使用wsimport工具生成其余工件,为SEI提供实现。将WebService应用程序部署到Eclipse Helios中的GlassFish(Glassfish适配器和Eclipse中安装的插件)。…

Java Applet的URLConnection与PHP无效 - java

我已经研究了Oracle文档和示例,但仍然无法正常工作。我有一个Java Applet,它只是尝试使用URLConnection和OutputStreamWriter通过POST将文本字段发送到PHP脚本。 Java方面似乎工作正常,没有引发异常,但是PHP在我的页面上未显示任何输出。我是PHP新手,因此请耐心等待。这是相关的Java部分: try { UR…

页面加载而不是提交时发生struts验证 - java

请原谅我;我对Struts有点陌生。我遇到一个问题,即页面加载而不是我实际提交表单时发生了验证。我整天都在论坛上搜寻和搜寻,没有任何运气。我显然做错了一些事情,应该很容易确定,但是我还没有发现问题所在。这是我的struts.xml的片段:<action name="*Test" method="{1}" clas…

休眠映射<键,设置<值>> - java

我有以下表格:@Entity @Table(name = "events") Event --id --name @Entity @Table(name = "state") State --id --name @Entity @Table(name = "action") Action --id …

DataSourceTransactionManager和JndiObjectFactoryBean和JdbcTemplate的用途是什么? - java

以下的用途是什么:org.springframework.jdbc.core.JdbcTemplate org.springframework.jdbc.datasource.DataSourceTransactionManager org.springframework.jndi.JndiObjectFactoryBean <tx:annotatio…