You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XAdES4j 2.2.0扩展XAdES-XL时HttpTsa配置异常求助

问题

使用XAdES4j 2.2.0进行XML文档签名,从1.5.1版本升级适配代码后,XADES-BES、XADES-T和XADES-C均可正常签名,但从XAdES-C扩展到XADES-XL时抛出异常:HttpTsaConfiguration must be configured in the profile in order to use an HTTP-based time-stamp token provider。

相关代码

// Certificate for signing is stored in PKCS12 keystore in file.
KeyingDataProvider keyingDataProvider = FileSystemKeyStoreKeyingDataProvider
        .builder("PKCS12", sKeyStorePath, new SigningCertificateSelector.single())
        .storePassword(new DirectPasswordProvider(sKeyStorePassword))
        .entryPassword(new DirectPasswordProvider(sKeyStorePassword))
        .fullChain(true)
        .build();

// KeyStore and CertStore for validating signatures and timestamps.
CertificateValidationProvider validationProvider = PKIXCertificateValidationProvider
        .builder(keyStore)
        .checkRevocation(true)
        .intermediateCertStores(certStore)
        .build();

// Read document from file on disk.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(new File(sFilePath));

// Sign document with XAdES-C.
signDocumentC(keyingDataProvider, doc, validationProvider);
// Sign document with XAdES-XL afterwards.
signDocumentXL(keyingDataProvider, doc, validationProvider);

...

/** Method for signing with XAdES-C. */
private void signDocumentC(KeyingDataProvider keyingDataProvider, Document doc, CertificateValidationProvider validationProvider) throws Exception
{
    Element elemToSign = doc.getDocumentElement();
    DOMHelper.useIdAsXmlId(elemToSign);

    ValidationDataProvider vdp = new ValidationDataFromCertValidationProvider(validationProvider);
    XadesSigner signer = new XadesCSigningProfile(keyingDataProvider, vdp)
        .with(new HttpTimeStampTokenProvider(new DefaultMessageDigestProvider(), new HttpTsaConfiguration("http://freetsa.org/tsr")))
        .newSigner();

    // Skip check for countersigning, just sign.
    new Enveloped(signer).sign(elemToSign);
}

/** Method for signing with XAdES-XL. */
private void signDocumentXL(KeyingDataProvider keyingProvider, Document doc, CertificateValidationProvider validationProvider) throws Exception
{
    Element elemToSign = doc.getDocumentElement();
    DOMHelper.useIdAsXmlId(elemToSign);

    NodeList signatures = doc.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE);
    Element signatureNode = (Element)signatures.item(signatures.getLength() - 1);

    XadesVerificationProfile nistVerificationProfile = new XadesVerificationProfile(validationProvider);

    XadesSignatureFormatExtender formExt = new XadesFormatExtenderProfile().getFormatExtender();
    XAdESVerificationResult res = nistVerificationProfile.newVerifier().verify(signatureNode, null, formExt, XAdESForm.X_L);
}

异常堆栈信息

[2023-01-23 18:22:29] INFO: [] ESignatureXML.signDocumentXL: Signing xml document XAdES-XL...
xades4j.production.PropertyDataGeneratorNotAvailableException: Property data generation failed for SigAndRefsTimeStamp: data object generator cannot be created
    at xades4j.production.PropertyDataGeneratorsMapperImpl.getGenerator(PropertyDataGeneratorsMapperImpl.java:51)
    at xades4j.production.PropertiesDataObjectsGeneratorImpl.doGenPropsData(PropertiesDataObjectsGeneratorImpl.java:87)
    at xades4j.production.PropertiesDataObjectsGeneratorImpl.genPropsData(PropertiesDataObjectsGeneratorImpl.java:73)
    at xades4j.production.PropertiesDataObjectsGeneratorImpl.generateUnsignedPropertiesData(PropertiesDataObjectsGeneratorImpl.java:64)
    at xades4j.production.XadesSignatureFormatExtenderImpl.enrichSignature(XadesSignatureFormatExtenderImpl.java:79)
    at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:497)
    at com.my.ESignatureXML.signDocumentXL(ESignatureXML.java:709)
    at com.my.ESignatureXML.signDocument(ESignatureXML.java:482)
    at com.my.ESignatureXML.performSigning(ESignatureXML.java:236)
    at com.my.ESignatureXML.sign(ESignatureXML.java:187)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
    at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) [Guice/ErrorInCustomProvider]: IllegalStateException: HttpTsaConfiguration must be configured in the profile in order to use an HTTP-based time-stamp token provider.
  at DefaultProductionBindingsModule.configure(DefaultProductionBindingsModule.java:80)
      \_ installed by: Modules$OverrideModule -> DefaultProductionBindingsModule
  at HttpTimeStampTokenProvider.<init>(HttpTimeStampTokenProvider.java:44)
      \_ for 2nd parameter
  while locating HttpTimeStampTokenProvider
  at DataGenSigAndRefsTimeStamp.<init>(DataGenSigAndRefsTimeStamp.java:51)
      \_ for 2nd parameter
  while locating DataGenSigAndRefsTimeStamp
  while locating PropertyDataObjectGenerator<SigAndRefsTimeStampProperty>

1 error

======================
Full classname legend:
======================
DataGenSigAndRefsTimeStamp:      "xades4j.production.DataGenSigAndRefsTimeStamp"
DefaultProductionBindingsModule: "xades4j.production.DefaultProductionBindingsModule"
HttpTimeStampTokenProvider:      "xades4j.providers.impl.HttpTimeStampTokenProvider"
Modules$OverrideModule:          "com.google.inject.util.Modules$OverrideModule"
PropertyDataObjectGenerator:     "xades4j.production.PropertyDataObjectGenerator"
SigAndRefsTimeStampProperty:     "xades4j.properties.SigAndRefsTimeStampProperty"
========================
End of classname legend:
========================

    at com.google.inject.internal.InternalProvisionException.toProvisionException(InternalProvisionException.java:251)
    at com.google.inject.internal.InjectorImpl$1.get(InjectorImpl.java:1104)
    at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1134)
    at xades4j.production.PropertyDataGeneratorsMapperImpl.getGenerator(PropertyDataGeneratorsMapperImpl.java:48)
    ... 58 more
Caused by: java.lang.IllegalStateException: HttpTsaConfiguration must be configured in the profile in order to use an HTTP-based time-stamp token provider.
    at xades4j.production.DefaultProductionBindingsModule.lambda$configure$0(DefaultProductionBindingsModule.java:81)
    at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:86)
    at com.google.inject.internal.InternalFactoryToInitializableAdapter.provision(InternalFactoryToInitializableAdapter.java:57)
    at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:60)
    at com.google.inject.internal.InternalFactoryToInitializableAdapter.get(InternalFactoryToInitializableAdapter.java:47)
    at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:40)
    at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:60)
    at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
    at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
    at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:300)
    at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:60)
    at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:40)
    at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:60)
    at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:113)
    at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:91)
    at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:300)
    at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:60)
    at com.google.inject.internal.InjectorImpl$1.get(InjectorImpl.java:1101)
    ... 60 more

排查发现,PropertiesDataObjectsGeneratorImpl的doGenPropsData方法中,xades4j.properties.SigAndRefsTimeStampProperty的time值为null,该异常仅在扩展到XAdES-XL时出现。


解决方案

问题根源是:扩展到XAdES-XL时需要添加SigAndRefsTimeStamp属性(新的时间戳),但当前的XadesFormatExtenderProfile没有配置时间戳服务(TSA)提供者。之前XAdES-C签名时配置的TSA只作用于C格式的签名器,和签名扩展器完全无关。

修改signDocumentXL方法,给XadesFormatExtenderProfile配置HTTP时间戳提供者,和XAdES-C签名时的配置保持一致:

/** Method for signing with XAdES-XL. */
private void signDocumentXL(KeyingDataProvider keyingProvider, Document doc, CertificateValidationProvider validationProvider) throws Exception
{
    Element elemToSign = doc.getDocumentElement();
    DOMHelper.useIdAsXmlId(elemToSign);

    NodeList signatures = doc.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE);
    Element signatureNode = (Element)signatures.item(signatures.getLength() - 1);

    XadesVerificationProfile nistVerificationProfile = new XadesVerificationProfile(validationProvider);

    // 给格式扩展器配置TSA提供者,和XAdES-C签名时的配置一致
    XadesSignatureFormatExtender formExt = new XadesFormatExtenderProfile()
            .with(new HttpTimeStampTokenProvider(new DefaultMessageDigestProvider(), new HttpTsaConfiguration("http://freetsa.org/tsr")))
            .getFormatExtender();

    XAdESVerificationResult res = nistVerificationProfile.newVerifier().verify(signatureNode, null, formExt, XAdESForm.X_L);
}

补充说明

XAdES-XL扩展过程需要生成新的时间戳属性来满足格式要求,这个过程依赖独立的TSA配置。之前的XAdES-C签名配置不会自动传递给扩展器,必须单独给XadesFormatExtenderProfile配置TSA提供者,才能生成所需的SigAndRefsTimeStamp属性,解决time值为null的问题。


内容的提问来源于stack exchange,提问作者predrags

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:25:39