如何使用JAVA在XML中添加多个签名

问题描述

我有以下使用JDom库,Apache XML安全性库,org.w3c.dom包和java.security包的方法,以使用来自单个PFX证书的数据对单个XML文件进行签名:

/** This method allows to sign a single XML using data from a single Certificate and a given Namespace

@param pKey Private Key obtained from a PFX certificate
@param cert Certificate data obtained from the PFX file
@param ns Namespace to be associated to the root tag of the signed XML content
**/
public void sign(PrivateKey pKey,X509Certificate cert,Namespace ns) throws JDOMException,InvalidKeyException,NoSuchAlgorithmException,SignatureException,XMLSecurityException,ParserConfigurationException,IOException,SAXException,DTECedidoException,TimbreException,CodigoException,ReciboException {
        Constants.setSignatureSpecnsprefix("");
        String baseUri = null;
        if (ns != null)
            baseUri = ns.getURI();
        String alg = pKey.getAlgorithm();
        if (!alg.equals(cert.getPublicKey().getAlgorithm()))
            throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        XMLUtil.getNiceXML(genDocument(ns),out);
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        org.w3c.dom.Document doc = db.parse(in);
        org.w3c.dom.Element root = doc.getDocumentElement();
        XMLSignature sig = null;
        if (alg.equals("RSA")) {
            if (!((RSAPrivateKey) pKey).getModulus().equals(((RSAPublicKey) cert.getPublicKey()).getModulus()))
                throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
            sig = new XMLSignature(doc,baseUri,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
        } else if (alg.equals("DSA")) {
            if (!(((DSAPrivateKey) pKey).getParams().getG()
                    .equals(((DSAPublicKey) cert.getPublicKey()).getParams().getG())
                    && ((DSAPrivateKey) pKey).getParams().getP()
                            .equals(((DSAPublicKey) cert.getPublicKey()).getParams().getP())
                    && ((DSAPrivateKey) pKey).getParams().getQ()
                            .equals(((DSAPublicKey) cert.getPublicKey()).getParams().getQ())))
                throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
            sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
        } else
            throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
        root.appendChild(sig.getElement());
        sig.addDocument("#" + getId());
        X509Data xdata = new X509Data(doc);
        xdata.addCertificate(cert);
        sig.getKeyInfo().addkeyvalue(cert.getPublicKey());
        sig.getKeyInfo().add(xdata);
        sig.sign(pKey);
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        DOMBuilder docIn = new DOMBuilder();
        Document domdoc = docIn.build(doc);
        cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
        this.signedDoc = bous.toByteArray();
    }

方法工作正常。但是,我需要重载它,并且新方法必须支持来自多个证书的数据(最多3个)。到目前为止,我有这个:

/** This method allows to sign a single XML using data from multiples Certificates and a given Namespace

@param pKey List of Private Keys obtained from one PFX certificate per key
@param cert List of Certificate datas obtained from one PFX file per data.
@param ns Namespace to be associated to the root tag of the signed XML content
**/
public void sign(List<PrivateKey> pKey,List<X509Certificate> cert,ReciboException {
        /* Loads the unsigned XML ENTIRE content in order to add the signatures*/
        Constants.setSignatureSpecnsprefix("");
        String baseUri = null;
        if (ns != null)
            baseUri = ns.getURI();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        XMLUtil.getNiceXML(genDocument(ns),out);
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        org.w3c.dom.Document doc = db.parse(in);
        org.w3c.dom.Element root = doc.getDocumentElement();
        XMLSignature sig = null;
        
        for(int i=0; i<pKey.size(); i++){
            PrivateKey pk=pKey.get(i);
            X509Certificate c=cert.get(i)
            String alg = pk.getAlgorithm();
            if (!alg.equals(c.getPublicKey().getAlgorithm()))
                throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
            if (alg.equals("RSA")) {
                if (!((RSAPrivateKey) pk).getModulus().equals(((RSAPublicKey) c.getPublicKey()).getModulus()))
                    throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
                sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
            } else if (alg.equals("DSA")) {
                if (!(((DSAPrivateKey) pk).getParams().getG()
                    .equals(((DSAPublicKey) c.getPublicKey()).getParams().getG())
                    && ((DSAPrivateKey) pk).getParams().getP()
                            .equals(((DSAPublicKey) c.getPublicKey()).getParams().getP())
                    && ((DSAPrivateKey) pk).getParams().getQ()
                            .equals(((DSAPublicKey) c.getPublicKey()).getParams().getQ())))
                    throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
                sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
            } else
                throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
            root.appendChild(sig.getElement());
            sig.addDocument("#" + getId());
            
            /* The following lines of code give me problems*/
            X509Data xdata = new X509Data(doc);
            xdata.addCertificate(c);

            sig.getKeyInfo().addkeyvalue(c.getPublicKey());
            sig.getKeyInfo().add(xdata);
            sig.sign(pk);
        
        }
        
        /* Generates and stores the byte content of the resulting
           signed XML */
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        DOMBuilder docIn = new DOMBuilder();
        Document domdoc = docIn.build(doc);
        cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
        this.signedDoc = bous.toByteArray();
    }

主要问题是以下几行代码从整个文档中获取信息,并且仅允许添加一个证书项目,而不是所有证书列表。

X509Data xdata = new X509Data(doc);
xdata.addCertificate(c); // !!!!!!!

sig.getKeyInfo().addkeyvalue(c.getPublicKey());
sig.getKeyInfo().add(xdata); //!!!!!!!
sig.sign(pk);

在哪里可以找到一个使用Java使用多个PFX文件中的信息对XML文件进行签名的好示例(我自己尝试过但没有成功)?

谢谢。

编辑 同时,我制作了这种方法,希望这是正确的方法

public void sign(List<PrivateKey> pKey,Namespace ns) 
        throws XMLSecurityException,CesionException {
        Constants.setSignatureSpecnsprefix("");
        String baseUri = null;
        if (ns != null)
            baseUri = ns.getURI();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        XMLUtil.getNiceXML(genDocument(ns),out);
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        org.w3c.dom.Document doc = db.parse(in);
        org.w3c.dom.Element root = doc.getDocumentElement();
        XMLSignature sig = null;
        for(int i=0; i<pKey.size(); i++) {
            PrivateKey pk=pKey.get(i);
            X509Certificate c=cert.get(i);
            String alg = pk.getAlgorithm();
            if (!alg.equals(c.getPublicKey().getAlgorithm()))
                throw (new CesionException(CesionException.NOT_CORRESPONDING));
            if (alg.equals("RSA")) {
                if (!((RSAPrivateKey) pk).getModulus().equals(((RSAPublicKey) c.getPublicKey()).getModulus()))
                    throw (new CesionException(CesionException.NOT_CORRESPONDING));
                sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
            } else if (alg.equals("DSA")) {
                if (!(((DSAPrivateKey) pk).getParams().getG()
                        .equals(((DSAPublicKey) c.getPublicKey()).getParams().getG())
                        && ((DSAPrivateKey) pk).getParams().getP()
                                .equals(((DSAPublicKey) c.getPublicKey()).getParams().getP())
                        && ((DSAPrivateKey) pk).getParams().getQ()
                                .equals(((DSAPublicKey) c.getPublicKey()).getParams().getQ())))
                    throw (new CesionException(CesionException.NOT_CORRESPONDING));
                sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
            } else
                throw (new CesionException(DTECedidoException.NOT_CORRESPONDING));
            root.appendChild(sig.getElement());
            sig.addDocument("#" + i);
            X509Data xdata = new X509Data(doc);
            xdata.addCertificate(c);
            sig.getKeyInfo().addkeyvalue(c.getPublicKey());
            sig.getKeyInfo().add(xdata);
            sig.sign(pk);
        }
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        DOMBuilder docIn = new DOMBuilder();
        Document domdoc = docIn.build(doc);
        cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
        this.signedDoc = bous.toByteArray();
    }

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...