如何将 XAdES-BES 转换为 XAdES-T。我使用 Xades4j 库。我有一个时间戳帐户。
我的SignerBes.class
package xades4j.production;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.signature.ObjectContainer;
import org.apache.xml.security.signature.Reference;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.ElementProxy;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import xades4j.UnsupportedAlgorithmException;
import xades4j.XAdES4jException;
import xades4j.XAdES4jXMLSigException;
import xades4j.properties.DataObjectDesc;
import xades4j.properties.QualifyingProperties;
import xades4j.properties.QualifyingProperty;
import xades4j.properties.SignedSignatureProperty;
import xades4j.properties.SigningCertificateProperty;
import xades4j.properties.UnsignedSignatureProperty;
import xades4j.properties.data.SigAndDataObjsPropertiesData;
import xades4j.providers.AlgorithmsProvider;
import xades4j.providers.BasicSignatureOptionsProvider;
import xades4j.providers.DataObjectPropertiesProvider;
import xades4j.providers.KeyingDataProvider;
import xades4j.providers.SignaturePropertiesProvider;
import xades4j.providers.SigningCertChainException;
import xades4j.utils.DOMHelper;
import xades4j.utils.ObjectUtils;
import xades4j.xml.marshalling.SignedPropertiesMarshaller;
import xades4j.xml.marshalling.UnsignedPropertiesMarshaller;
import com.google.inject.Inject;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.signature.SignedInfo;
import org.w3c.dom.Document;
import xades4j.providers.MessageDigestEngineProvider;
import xades4j.providers.impl.DefaultMessageDigestProvider;
/**
* Base logic for producing XAdES signatures (XAdES-BES).
*
* @author Luis
* @author murat.demir
*/
class SignerBES implements XadesSigner {
static {
Init.initXMLSec();
// Security.addProvider(new RemoteTokenProvider());
}
/**/
private final KeyingDataProvider keyingProvider;
private final AlgorithmsProvider algorithmsProvider;
private final PropertiesDataObjectsGenerator propsDataObjectsGenerator;
private final SignedPropertiesMarshaller signedPropsMarshaller;
private final UnsignedPropertiesMarshaller unsignedPropsMarshaller;
/**/
private final DataObjectDescsProcessor dataObjectDescsProcessor;
private final KeyInfoBuilder keyInfoBuilder;
private final QualifyingPropertiesProcessor qualifPropsProcessor;
/**/
private MessageDigestEngineProvider messageDigestEngineProvider = null;
private XMLSignature signature = null;
private X509Certificate x509Certificate = null;
private String signatureId = null;
private PropertiesDataGenerationContext propsDataGenCtx = null;
private QualifyingProperties qualifProps = null;
private Element qualifyingPropsElem = null;
private Document signatureDocument = null;
@Inject
protected SignerBES(KeyingDataProvider keyingProvider, AlgorithmsProvider algorithmsProvider, BasicSignatureOptionsProvider basicSignatureOptionsProvider, SignaturePropertiesProvider signaturePropsProvider, DataObjectPropertiesProvider dataObjPropsProvider, PropertiesDataObjectsGenerator propsDataObjectsGenerator, SignedPropertiesMarshaller signedPropsMarshaller, UnsignedPropertiesMarshaller unsignedPropsMarshaller) {
if (ObjectUtils.anyNull(keyingProvider, algorithmsProvider, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator,
signedPropsMarshaller, unsignedPropsMarshaller)) {
throw new NullPointerException("One or more arguments are null");
}
this.keyingProvider = keyingProvider;
this.algorithmsProvider = algorithmsProvider;
this.propsDataObjectsGenerator = propsDataObjectsGenerator;
this.signedPropsMarshaller = signedPropsMarshaller;
this.unsignedPropsMarshaller = unsignedPropsMarshaller;
this.dataObjectDescsProcessor = new DataObjectDescsProcessor(algorithmsProvider);
this.keyInfoBuilder = new KeyInfoBuilder(basicSignatureOptionsProvider, algorithmsProvider);
this.qualifPropsProcessor = new QualifyingPropertiesProcessor(signaturePropsProvider, dataObjPropsProvider);
this.messageDigestEngineProvider = new DefaultMessageDigestProvider();
}
//------------------------------ for Remote Signature -------------------------------------
@Override
public XadesSignatureResult sign(byte[] signedHash) throws Exception {
this.signature.setSignatureValueElement(signedHash);
// Set the ds:SignatureValue id.
Element sigValueElem = DOMHelper.getFirstDescendant(this.signature.getElement(), Constants.SignatureSpecNS, Constants._TAG_SIGNATUREVALUE);
sigValueElem.setAttributeNS(null, Constants._ATT_ID, String.format("%s-sigvalue", signatureId));
/* Marshal unsigned properties */
// Generate the unsigned properties data objects. The data objects
// structure
// is verifier in the process.
this.propsDataGenCtx.setTargetXmlSignature(this.signature);
SigAndDataObjsPropertiesData unsignedPropsData = this.propsDataObjectsGenerator.generateUnsignedPropertiesData(this.qualifProps.getUnsignedProperties(), this.propsDataGenCtx);
// Marshal the unsigned properties to the final QualifyingProperties node.
this.unsignedPropsMarshaller.marshal(unsignedPropsData, String.format("%s-unsignedprops", this.signatureId), this.qualifyingPropsElem);
return new XadesSignatureResult(this.signature, this.qualifProps);
}
@Override
public byte[] prepareDataToSign(SignedDataObjects signedDataObjects, Node parent, X509Certificate certificate) throws XAdES4jException {
if (null == signedDataObjects) {
throw new NullPointerException("References cannot be null");
}
if (null == parent) {
throw new NullPointerException("Parent node cannot be null");
}
if (signedDataObjects.isEmpty()) {
throw new IllegalArgumentException("Data objects list is empty");
}
this.signatureDocument = DOMHelper.getOwnerDocument(parent);
// Generate unique identifiers for the Signature and the
// SignedProperties.
this.signatureId = String.format("xmldsig-%s", UUID.randomUUID());
String signedPropsId = String.format("%s-signedprops", signatureId);
// Signing certificate chain (may contain only the signing certificate).
this.x509Certificate = certificate;
List<X509Certificate> signingCertificateChain = new ArrayList<X509Certificate>();
signingCertificateChain.add(this.x509Certificate);
if (null == signingCertificateChain || signingCertificateChain.isEmpty()) {
throw new SigningCertChainException("Signing certificate not provided");
}
// Get the specific signature algorithm for the key's algorithm.
String sigAlgUri = this.algorithmsProvider.getSignatureAlgorithm(this.x509Certificate.getPublicKey().getAlgorithm());
if (null == sigAlgUri) {
throw new NullPointerException("Signature algorithm URI not provided");
}
String canonAlgUri = this.algorithmsProvider.getCanonicalizationAlgorithmForSignature();
if (null == canonAlgUri) {
throw new NullPointerException("Canonicalization algorithm URI not provided");
}
String digestAlgUri = this.algorithmsProvider.getDigestAlgorithmForDataObjsReferences();
if (null == digestAlgUri) {
throw new NullPointerException("Digest algorithm URI not provided");
}
try {
this.signature = new XMLSignature(this.signatureDocument, signedDataObjects.getBaseUri(), sigAlgUri, canonAlgUri);
this.signature.setId(this.signatureId);
} catch (XMLSecurityException ex) {
// Following the code, doesn't seem to be thrown at all.
throw new XAdES4jXMLSigException(ex.getMessage());
}
/* References */
// Process the data object descriptions to get the References and
// mappings.
// After this call all the signed data objects References and XMLObjects
// are added to the signature.
Map<DataObjectDesc, Reference> referenceMappings = this.dataObjectDescsProcessor.process(signedDataObjects.getDataObjectsDescs(), this.signature);
/* SignedProperties reference */
// XAdES 6.3.1: "In order to protect the properties with the signature,
// a ds:Reference element MUST be added to the XMLDSIG signature (...)
// composed in such a way that it uses the SignedProperties element
// (...)
// as the input for computing its corresponding digest. Additionally,
// (...) use the Type attribute of this particular ds:Reference element,
// with its value set to: http://uri.etsi.org/01903#SignedProperties."
try {
this.signature.addDocument('#' + signedPropsId, null, digestAlgUri, null, QualifyingProperty.SIGNED_PROPS_TYPE_URI);
} catch (XMLSignatureException ex) {
// Seems to be thrown when the digest algorithm is not supported. In
// this case, if it wasn't thrown when processing the data objects
// it
// shouldn't be thrown now!
throw new UnsupportedAlgorithmException("Digest algorithm not supported in the XML Signature provider: " + ex.getMessage(), digestAlgUri);
}
/* QualifyingProperties element */
// Create the QualifyingProperties element
this.qualifyingPropsElem = ElementProxy.createElementForFamily(this.signature.getDocument(), QualifyingProperty.XADES_XMLNS, QualifyingProperty.QUALIFYING_PROPS_TAG);
this.qualifyingPropsElem.setAttributeNS(null, QualifyingProperty.TARGET_ATTR, '#' + this.signatureId);
this.qualifyingPropsElem.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:xades141", QualifyingProperty.XADESV141_XMLNS);
// ds:Object to contain QualifyingProperties
ObjectContainer qPropsXmlObj = new ObjectContainer(signature.getDocument());
qPropsXmlObj.appendChild(this.qualifyingPropsElem);
try {
this.signature.appendObject(qPropsXmlObj);
} catch (XMLSignatureException ex) {
// -> xmlSignature.appendObject(xmlObj): not thrown when signing.
throw new IllegalStateException(ex);
}
/* Collect the properties */
// Get the format specific signature properties.
Collection<SignedSignatureProperty> fsssp = new ArrayList<SignedSignatureProperty>(2);
Collection<UnsignedSignatureProperty> fsusp = new ArrayList<UnsignedSignatureProperty>(2);
getFormatSpecificSignatureProperties(fsssp, fsusp, signingCertificateChain);
// Gather all the signature and data objects properties.
this.qualifProps = this.qualifPropsProcessor.getQualifyingProperties(signedDataObjects, fsssp, fsusp);
/* Marshal the signed properties */
// Create the context for signed properties data objects generation.
this.propsDataGenCtx = new PropertiesDataGenerationContext(signedDataObjects.getDataObjectsDescs(), referenceMappings, parent, this.algorithmsProvider);
// Generate the signed properties data objects. The data objects
// structure
// is verifier in the process.
SigAndDataObjsPropertiesData signedPropsData = this.propsDataObjectsGenerator.generateSignedPropertiesData(this.qualifProps.getSignedProperties(), this.propsDataGenCtx);
// Marshal the signed properties data to the QualifyingProperties node.
this.signedPropsMarshaller.marshal(signedPropsData, signedPropsId, this.qualifyingPropsElem);
/* ds:KeyInfo */
this.keyInfoBuilder.buildKeyInfo(this.x509Certificate, this.signature);
try {
parent.appendChild(this.signature.getElement());
try {
SignedInfo si = this.signature.getSignedInfo();
si.generateDigestValues();
byte[] data = si.getCanonicalizedOctetStream();
// byte[] raw = this.signature.getDataToSign();
// MessageDigest messageDigest = this.messageDigestEngineProvider.getEngine(digestAlgUri);
// byte[] digestedData = messageDigest.digest(raw);
// DigestInfo dInfo = new DigestInfo(new AlgorithmIdentifier(new DERObjectIdentifier(NISTObjectIdentifiers.id_sha256.getId()), new DERNull()), digestedData);
// byte[] der = dInfo.getEncoded("DER");
// return this.signature.getDataToSign();
return data;
} catch (XMLSignatureException ex) {
throw new XAdES4jXMLSigException(ex.getMessage(), ex);
} catch (InvalidCanonicalizerException ex) {
ex.printStackTrace();
} catch (XMLSecurityException ex) {
ex.printStackTrace();
}
} catch (XAdES4jException ex) {
parent.removeChild(signature.getElement());
throw ex;
}
return null;
}
}
我已经修改了 SignerBes 类。我的签名操作分为两个部分。
- 第一步,prepareDataToSign()
- 第二步,sign()
到目前为止对 Xades-Bes 格式很好。我想将 Xades-Bes 转换为 Xades-T