xades4j.UnsupportedAlgorithmException:XML签名提供程序上的不受支持的转换

时间:2014-05-08 14:34:19

标签: java xades4j xml-dsig

我正在尝试为给定的blob创建XAdES-BES签名。对于此签名,我需要在签名之前在内容上添加两个转换:Base64(http://www.w3.org/2000/09/xmldsig#base64)&一个自定义的(称为可选 - deflate)。

问题在于可选的转换。我试图弄清楚如何实现自定义变换,注册它,最后让Xades4J使用它。

到目前为止,我想了很多(感谢Google和很多时间),所以我大致相信:我有一个Provider类,在构造函数中放置新的TransformService;在我的主代码中,我将我的Provider添加到Security实例中;然后,我尝试将变换添加到我的实际待签名对象。

不幸的是,我总是得到同样的错误:

Exception in thread "main" xades4j.UnsupportedAlgorithmException: Unsupported transform on XML Signature provider (urn:xml:sig:transform:optional-deflate)
    at xades4j.production.DataObjectDescsProcessor.processTransforms(DataObjectDescsProcessor.java:194)
    at xades4j.production.DataObjectDescsProcessor.process(DataObjectDescsProcessor.java:87)
    at xades4j.production.SignerBES.sign(SignerBES.java:173)
    at xades4j.production.SignerBES.sign(SignerBES.java:122)
    at com.mycompany.Test.createXades(Test.java:199)
    at com.mycompany.Test.main(Test.java:47)
Caused by: org.apache.xml.security.transforms.TransformationException: Unknown transformation. No handler installed for URI urn:xml:sig:transform:optional-deflate
Original Exception was org.apache.xml.security.transforms.InvalidTransformException: Unknown transformation. No handler installed for URI urn:xml:sig:transform:optional-deflate
    at org.apache.xml.security.transforms.Transforms.addTransform(Unknown Source)
    at xades4j.production.DataObjectDescsProcessor.processTransforms(DataObjectDescsProcessor.java:185)
    ... 5 more

所以,我的代码看起来像这样(缩写为我认为必要的):

TransformService上课:

package com.mycompany.security;

import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;

import javax.xml.crypto.Data;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.TransformService;
import javax.xml.crypto.dsig.TransformException;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;

public class OptionalDeflateTransform extends TransformService {
    public AlgorithmParameterSpec getParameterSpec() {
            return null;
    }
    public Data transform(Data data, XMLCryptoContext context) throws TransformException {
            return null;
    }
    public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException {
            return null;
    }
    public boolean isFeatureSupported(String feature) {
            return false;
    }
    public void init(TransformParameterSpec params) throws InvalidAlgorithmParameterException {}
    public void marshalParams(XMLStructure parent, XMLCryptoContext context) throws MarshalException {}
    public void init(XMLStructure parent, XMLCryptoContext context) throws InvalidAlgorithmParameterException {}
}

Provider子类:

package com.mycompany.security;

import java.security.Provider;

public final class OptionalDeflateProvider extends Provider {
    private static final long serialVersionUID = 8849833178389029123L;

    public OptionalDeflateProvider() {
            super("OptionalDeflate", 1.0, "OptionalDeflate provider 1.0 implementing the OptionalDeflate transform algorithm.");
            put("TransformService.urn:xml:sig:transform:optional-deflate", "com.mycompany.security.OptionalDeflateTransform");
    }

}

最后,我的主Test类,其中包含实际签名。如果没有这种转换,它就可以工作(但是,并没有添加转换,这是必要的)。所以Base64可以工作。

protected static void createXades(String content) throws Exception {
    /*Get certificate & private key*/
    Certificates c = new Certificates(); 
    c.initSession(); //some helper class where I can get my certificate & private key for signing

    /*Create a document*/
    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
    Document doc = docBuilder.newDocument();
    Element objectElement = doc.createElement("object");
    doc.appendChild(objectElement);
    Element requestElement = doc.createElement("request");
    requestElement.appendChild(doc.createTextNode(content));
    requestElement.setAttribute("ID", UUID.randomUUID().toString());
    objectElement.appendChild(requestElement);

    /*Key provider, signing profile & signer itself*/
    KeyingDataProvider kp = new CustomKeyingDataProvider(c.getCertificate(), c.getPrivateKey());
    XadesSigningProfile p = new XadesBesSigningProfile(kp);
    p.withAlgorithmsProviderEx(new ProviderEx());
    XadesSigner signer = p.newSigner();

    /*Add the optional deflate provider*/
    Security.addProvider(new OptionalDeflateProvider());
    System.out.println("--- installed providers ---");
    for (Provider pr : Security.getProviders())
            System.out.println(pr.getName());
    System.out.println("---");

    /*Test if we can get the transformservice-instance*/
    TransformService ts = TransformService.getInstance("urn:xml:sig:transform:optional-deflate", "DOM");
    System.out.println(ts.getAlgorithm());
    System.out.println("---");

    /*Signed data*/
    DataObjectDesc flatFile = new DataObjectReference("#" + requestElement.getAttribute("ID"))
            .withTransform(new GenericAlgorithm("http://www.w3.org/2000/09/xmldsig#base64"))
            .withTransform(new GenericAlgorithm("urn:xml:sig:transform:optional-deflate"));
    SignedDataObjects dataObjs = new SignedDataObjects(flatFile);

    /*Actual signing*/
    signer.sign(dataObjs, objectElement);
    log(objectElement.getLastChild());
}

你可以看到我打印出一些东西。我举例说,安装工作正常,我也记录了已安装的提供程序。我得到这个作为输出:

--- installed providers ---
SUN
SunRsaSign
SunEC
SunJSSE
SunJCE
SunJGSS
SunSASL
XMLDSig
SunPCSC
SunMSCAPI
OptionalDeflate
---
urn:xml:sig:transform:optional-deflate
---

据我所知,提供商已经成功注册,转换服务可以毫无问题地加载,......所以我真的不知道发生了什么?

我也检查了Xades4j的源代码,并且.withTransform(new GenericAlgorithm("urn:xml:sig:transform:optional-deflate"))内部发生的事情非常简单:

import org.apache.xml.security.transforms.Transforms;

...

private Transforms processTransforms(DataObjectDesc dataObjDesc, Document document) throws UnsupportedAlgorithmException {
    Collection<Algorithm> dObjTransfs = dataObjDesc.getTransforms();
    if (dObjTransfs.isEmpty()) {
        return null;
    }
    Transforms transforms = new Transforms(document);
    for (Algorithm dObjTransf : dObjTransfs) {
        try {
            List<Node> transfParams = this.algorithmsParametersMarshaller.marshalParameters(dObjTransf, document);
            if (null == transfParams) {
                transforms.addTransform(dObjTransf.getUri());
            } else {
                transforms.addTransform(dObjTransf.getUri(), DOMHelper.nodeList(transfParams));
            }
        } catch (TransformationException ex) {
            throw new UnsupportedAlgorithmException("Unsupported transform on XML Signature provider", dObjTransf.getUri(), ex);
        }
    }
    return transforms;
}

引发错误的确切行是transforms.addTransform(dObjTransf.getUri())。这个transforms对象是一个标准&#39; apache对象(org.apache.xml.security.transforms.Transforms对象)。所以我猜它应该能够像我在代码中那样得到相同的TransformService两行高吗?但它不是吗?

任何可以指出我失踪的人?我将永远感激不尽。

1 个答案:

答案 0 :(得分:2)

显然,Apache Santuario loads transforms from a internal map。有一个register 您可能可以用来注册自定义转换的方法。