/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.xmlsecurity.processor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.component.xmlsecurity.api.KeyAccessor;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureConstants;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureException;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureFormatException;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureHelper;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureInvalidKeyException;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureNoKeyException;
import org.apache.camel.component.xmlsecurity.api.XmlSignatureProperties;
import org.apache.camel.util.IOHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Creates from the message body a XML signature element which is returned in
* the message body of the output message. Enveloped and enveloping XML
* signatures are supported.
* <p>
* In the enveloped XML signature case, the method
* {@link XmlSignerConfiguration#getParentLocalName()} must not return
* <code>null</code>. In this case the parent element must be contained in the
* XML document provided by the message body and the signature element is added
* as last child element of the parent element. If a KeyInfo instance is
* provided by the {@link KeyAccessor} and
* {@link XmlSignerConfiguration#getAddKeyInfoReference()} is <code>true</code>,
* then also a reference to the KeyInfo element is added. The generated XML
* signature has the following structure:
*
* <pre>
* {@code
* <[parent element]>
* ...
* <Signature Id="[signature_id]">
* <SignedInfo>
* <Reference URI="">
* <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
* (<Transform>)*
* <DigestMethod>
* <DigestValue>
* </Reference>
* (<Reference URI="#[keyinfo_Id]">
* <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
* <DigestMethod>
* <DigestValue>
* </Reference>)?
* <!-- further references possible, see XmlSignerConfiguration#setProperties(XmlSignatureProperties) -->
* </SignedInfo>
* <SignatureValue>
* (<KeyInfo Id="[keyinfo_id]">)?
* <!-- Object elements possible, see XmlSignerConfiguration#setProperties(XmlSignatureProperties) -->
* </Signature>
* </[parent element]>
* }
* </pre>
* <p>
* In the enveloping XML signature case, the generated XML signature has the
* following structure:
*
* <pre>
* {@code
* <Signature Id="[signature_id]">
* <SignedInfo>
* <Reference URI="#[object_id]" type="[optional_type_value]">
* (<Transform>)*
* <DigestMethod>
* <DigestValue>
* </Reference>
* (<Reference URI="#[keyinfo_id]">
* <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
* <DigestMethod>
* <DigestValue>
* </Reference>)?
* <!-- further references possible, see XmlSignerConfiguration#setProperties(XmlSignatureProperties) -->
* </SignedInfo>
* <SignatureValue>
* (<KeyInfo Id="[keyinfo_id]">)?
* <Object Id="[object_id]"/>
* <!-- further Object elements possible, see XmlSignerConfiguration#setProperties(XmlSignatureProperties) -->
* </Signature>
* }
* </pre>
*
* In the enveloping XML signature case, also message bodies containing plain
* text are supported. This must be indicated via the header
* {@link XmlSignatureConstants#HEADER_MESSAGE_IS_PLAIN_TEXT} or via the
* configuration {@link XmlSignerConfiguration#getPlainText()}.
*
* <p>
* In both cases, the digest algorithm is either read from the configuration
* method {@link XmlSignerConfiguration#getDigestAlgorithm()} or calculated from
* the signature algorithm (
* {@link XmlSignerConfiguration#getSignatureAlgorithm()}. The optional
* transforms are read from {@link XmlSignerConfiguration#getTransformMethods()}
* .
* <p>
* In both cases, you can add additional references and objects which contain
* properties for the XML signature, see
* {@link XmlSignerConfiguration#setProperties(XmlSignatureProperties)}.
*/
public class XmlSignerProcessor extends XmlSignatureProcessor {
private static final Logger LOG = LoggerFactory.getLogger(XmlSignerProcessor.class);
private static final String SHA512 = "sha512";
private static final String SHA384 = "sha384";
private static final String SHA256 = "sha256";
private static final String SHA1 = "sha1";
private static final String HTTP_WWW_W3_ORG_2001_04_XMLDSIG_MORE_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384";
private final XmlSignerConfiguration config;
public XmlSignerProcessor(XmlSignerConfiguration config) {
super();
this.config = config;
}
@Override
public XmlSignerConfiguration getConfiguration() {
return config;
}
@Override
public void process(Exchange exchange) throws Exception { //NOPMD
try {
LOG.debug("XML signature generation started using algorithm {} and canonicalization method {}", getConfiguration()
.getSignatureAlgorithm(), getConfiguration().getCanonicalizationMethod().getAlgorithm());
// lets setup the out message before we invoke the signing
// so that it can mutate it if necessary
Message out = exchange.getOut();
out.copyFrom(exchange.getIn());
Document outputDoc = sign(out);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
XmlSignatureHelper.transformNonTextNodeToOutputStream(outputDoc, outStream, omitXmlDeclaration(out));
byte[] data = outStream.toByteArray();
out.setBody(data);
clearMessageHeaders(out);
LOG.debug("XML signature generation finished");
} catch (Exception e) {
// remove OUT message, as an exception occurred
exchange.setOut(null);
throw e;
}
}
protected Document sign(final Message out) throws Exception { //NOPMD
try {
XMLSignatureFactory fac;
// Try to install the Santuario Provider - fall back to the JDK provider if this does
// not work
try {
fac = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig");
} catch (NoSuchProviderException ex) {
fac = XMLSignatureFactory.getInstance("DOM");
}
final Node node = getMessageBodyNode(out);
Node parent = getParentOfSignature(out, node);
final KeySelector keySelector = getConfiguration().getKeyAccessor().getKeySelector(out);
if (keySelector == null) {
throw new XmlSignatureNoKeyException(
"Key selector is missing for XML signature generation. Specify a key selector in the configuration.");
}
// the method KeyAccessor.getKeyInfo must be called after the method KeyAccessor.getKeySelector, this is part of the interface contract!
final KeyInfo keyInfo = getConfiguration().getKeyAccessor().getKeyInfo(out, node, fac.getKeyInfoFactory());
final String signatureId = "_" + UUID.randomUUID().toString();
LOG.debug("Signature Id {}", signatureId);
XmlSignatureProperties.Input input = new InputBuilder().contentDigestAlgorithm(getDigestAlgorithmUri()).keyInfo(keyInfo)
.message(out).messageBodyNode(node).parent(parent).signatureAlgorithm(getConfiguration().getSignatureAlgorithm())
.signatureFactory(fac).signatureId(signatureId).build();
XmlSignatureProperties.Output properties = getSignatureProperties(input);
List<? extends XMLObject> objects = getObjects(input, properties);
List<? extends Reference> refs = getReferences(input, properties, getKeyInfoId(keyInfo));
SignedInfo si = createSignedInfo(fac, refs);
if (parent == null) {
// for enveloping signature, create new document
parent = XmlSignatureHelper.newDocumentBuilder(Boolean.TRUE).newDocument();
}
DOMSignContext dsc = createAndConfigureSignContext(parent, keySelector);
XMLSignature signature = fac.newXMLSignature(si, keyInfo, objects, signatureId, null);
// generate the signature
signature.sign(dsc);
return XmlSignatureHelper.getDocument(parent);
} catch (XMLSignatureException se) {
if (se.getCause() instanceof InvalidKeyException) {
throw new XmlSignatureInvalidKeyException(se.getMessage(), se);
} else {
throw new XmlSignatureException(se);
}
} catch (GeneralSecurityException e) {
// like NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException
throw new XmlSignatureException(e);
}
}
protected XmlSignatureProperties.Output getSignatureProperties(XmlSignatureProperties.Input input) throws Exception { //NOPMD
XmlSignatureProperties propGetter = getConfiguration().getProperties();
XmlSignatureProperties.Output propsOutput = null;
if (propGetter != null) {
propsOutput = propGetter.get(input);
}
return propsOutput;
}
private DOMSignContext createAndConfigureSignContext(Node parent, KeySelector keySelector) {
DOMSignContext dsc = new DOMSignContext(keySelector, parent);
// set namespace prefix for "http://www.w3.org/2000/09/xmldsig#" according to best practice described in http://www.w3.org/TR/xmldsig-bestpractices/#signing-xml-without-namespaces
if (getConfiguration().getPrefixForXmlSignatureNamespace() != null
&& !getConfiguration().getPrefixForXmlSignatureNamespace().isEmpty()) {
dsc.putNamespacePrefix("http://www.w3.org/2000/09/xmldsig#", getConfiguration().getPrefixForXmlSignatureNamespace());
}
setCryptoContextProperties(dsc);
setUriDereferencerAndBaseUri(dsc);
return dsc;
}
protected Boolean omitXmlDeclaration(Message message) {
Boolean omitXmlDeclaration = message.getHeader(XmlSignatureConstants.HEADER_OMIT_XML_DECLARATION, Boolean.class);
if (omitXmlDeclaration == null) {
omitXmlDeclaration = getConfiguration().getOmitXmlDeclaration();
}
if (omitXmlDeclaration == null) {
omitXmlDeclaration = Boolean.FALSE;
}
LOG.debug("Omit XML declaration: {}", omitXmlDeclaration);
return omitXmlDeclaration;
}
protected SignedInfo createSignedInfo(XMLSignatureFactory fac, List<? extends Reference> refs) throws Exception { //NOPMD
return fac.newSignedInfo(fac.newCanonicalizationMethod(getConfiguration().getCanonicalizationMethod().getAlgorithm(),
(C14NMethodParameterSpec) getConfiguration().getCanonicalizationMethod().getParameterSpec()),
getSignatureMethod(getConfiguration().getSignatureAlgorithm(), fac), refs);
}
private SignatureMethod getSignatureMethod(String signatureAlgorithm, XMLSignatureFactory fac) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
return fac.newSignatureMethod(signatureAlgorithm, null);
}
protected Node getMessageBodyNode(Message message) throws Exception { //NOPMD
InputStream is = message.getMandatoryBody(InputStream.class);
Boolean isPlainText = isPlainText(message);
Node node;
if (isPlainText != null && isPlainText) {
node = getTextNode(message, is);
} else {
Document doc = parseInput(is, getConfiguration().getDisallowDoctypeDecl());
node = doc.getDocumentElement();
LOG.debug("Root element of document to be signed: {}", node);
}
return node;
}
protected Boolean isPlainText(Message message) {
Boolean isPlainText = message.getHeader(XmlSignatureConstants.HEADER_MESSAGE_IS_PLAIN_TEXT, Boolean.class);
if (isPlainText == null) {
isPlainText = getConfiguration().getPlainText();
}
LOG.debug("Is plain text: {}", isPlainText);
return isPlainText;
}
protected Element getParentOfSignature(Message inMessage, Node messageBodyNode) throws Exception { //NOPMD
if (getConfiguration().getParentLocalName() == null) {
return null;
}
if (messageBodyNode.getParentNode() == null || messageBodyNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE) {
throw new XmlSignatureFormatException(
"Incomming message has wrong format: It is not an XML document. Cannot create an enveloped XML signature.");
}
Document doc = (Document) messageBodyNode.getParentNode();
NodeList parents = doc.getElementsByTagNameNS(getConfiguration().getParentNamespace(), getConfiguration().getParentLocalName());
if (parents == null || parents.getLength() == 0) {
throw new XmlSignatureFormatException(
String.format(
"Incoming message has wrong format: The parent element with the local name %s and the namespace %s was not found in the message to build an enveloped XML signature.",
getConfiguration().getParentLocalName(), getConfiguration().getParentNamespace()));
}
// return the first element
return (Element) parents.item(0);
}
protected List<? extends Reference> getReferences(XmlSignatureProperties.Input input, XmlSignatureProperties.Output properties,
String keyInfoId) throws Exception { //NOPMD
// Create Reference with URI="#<objectId>" for enveloping signature or URI="" for enveloped signature and the transforms
Reference ref = createReference(input.getSignatureFactory(), getContentReferenceUri(input.getMessage()),
getContentReferenceType(input.getMessage()));
Reference keyInfoRef = createKeyInfoReference(input.getSignatureFactory(), keyInfoId, input.getContentDigestAlgorithm());
int propsRefsSize = properties == null || properties.getReferences() == null || properties.getReferences().isEmpty() ? 0
: properties.getReferences().size();
int size = keyInfoRef == null ? propsRefsSize + 1 : propsRefsSize + 2;
List<Reference> referenceList = new ArrayList<Reference>(size);
referenceList.add(ref);
if (keyInfoRef != null) {
referenceList.add(keyInfoRef);
}
if (properties != null && properties.getReferences() != null && !properties.getReferences().isEmpty()) {
referenceList.addAll(properties.getReferences());
}
return referenceList;
}
protected List<? extends XMLObject> getObjects(XmlSignatureProperties.Input input, XmlSignatureProperties.Output properties)
throws Exception { //NOPMD
if (isEnveloped()) {
if (properties == null || properties.getObjects() == null) {
return Collections.emptyList();
}
return properties.getObjects();
}
final String objectId = getConfiguration().getContentObjectId();
LOG.debug("Object Content Id {}", objectId);
XMLObject obj = createXMLObject(input.getSignatureFactory(), input.getMessageBodyNode(), objectId);
if (properties == null || properties.getObjects() == null || properties.getObjects().isEmpty()) {
return Collections.singletonList(obj);
}
List<XMLObject> result = new ArrayList<XMLObject>(properties.getObjects().size() + 1);
result.add(obj);
result.addAll(properties.getObjects());
return result;
}
private Node getTextNode(Message inMessage, InputStream is) throws IOException, ParserConfigurationException, XmlSignatureException {
LOG.debug("Message body to be signed is plain text");
String encoding = getMessageEncoding(inMessage);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, bos);
try {
String text = new String(bos.toByteArray(), encoding);
return XmlSignatureHelper.newDocumentBuilder(true).newDocument().createTextNode(text);
} catch (UnsupportedEncodingException e) {
throw new XmlSignatureException(String.format("The message encoding %s is not supported.", encoding), e);
}
}
protected String getMessageEncoding(Message inMessage) {
String encoding = inMessage.getHeader(XmlSignatureConstants.HEADER_PLAIN_TEXT_ENCODING, String.class);
if (encoding == null) {
encoding = getConfiguration().getPlainTextEncoding();
}
LOG.debug("Messge encoding: {}", encoding);
return encoding;
}
protected Document parseInput(InputStream is, Boolean disallowDoctypeDecl) throws XmlSignatureFormatException,
ParserConfigurationException, IOException {
try {
return XmlSignatureHelper.newDocumentBuilder(disallowDoctypeDecl).parse(is);
} catch (SAXException e) {
throw new XmlSignatureFormatException(
"XML signature generation not possible. Sent message is not an XML document. Check the sent message.", e);
} finally {
IOHelper.close(is, "input stream");
}
}
protected Reference createReference(XMLSignatureFactory fac, String uri, String type) throws InvalidAlgorithmParameterException,
XmlSignatureException {
try {
List<Transform> transforms = getTransforms(fac);
Reference ref = fac.newReference(uri, fac.newDigestMethod(getDigestAlgorithmUri(), null), transforms, type, null);
return ref;
} catch (NoSuchAlgorithmException e) {
throw new XmlSignatureException("Wrong algorithm specified in the configuration.", e);
}
}
protected String getContentReferenceType(Message message) {
String type = message.getHeader(XmlSignatureConstants.HEADER_CONTENT_REFERENCE_TYPE, String.class);
if (type == null) {
type = getConfiguration().getContentReferenceType();
}
LOG.debug("Content reference type: {}", type);
return type;
}
protected String getContentReferenceUri(Message message) {
String uri = message.getHeader(XmlSignatureConstants.HEADER_CONTENT_REFERENCE_URI, String.class);
if (uri == null) {
uri = getConfiguration().getContentReferenceUri();
}
if (uri == null) {
uri = isEnveloped() ? "" : "#" + getConfiguration().getContentObjectId();
}
LOG.debug("Content reference uri: {}", uri);
return uri;
}
protected XMLObject createXMLObject(XMLSignatureFactory fac, Node node, String id) {
return fac.newXMLObject(Collections.singletonList(new DOMStructure(node)), id, null, null);
}
private List<Transform> getTransforms(XMLSignatureFactory fac) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
boolean isEnveloped = isEnveloped();
List<AlgorithmMethod> configuredTrafos = getConfiguration().getTransformMethods();
if (isEnveloped) {
// add enveloped transform if necessary
if (configuredTrafos.size() > 0) {
if (!containsEnvelopedTransform(configuredTrafos)) {
configuredTrafos = new ArrayList<AlgorithmMethod>(configuredTrafos.size() + 1);
configuredTrafos.add(XmlSignatureHelper.getEnvelopedTransform());
configuredTrafos.addAll(getConfiguration().getTransformMethods());
}
} else {
// add enveloped and C14N trafo
configuredTrafos = new ArrayList<AlgorithmMethod>(2);
configuredTrafos.add(XmlSignatureHelper.getEnvelopedTransform());
configuredTrafos.add(XmlSignatureHelper.getCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE));
}
}
List<Transform> transforms = new ArrayList<Transform>(configuredTrafos.size());
for (AlgorithmMethod trafo : configuredTrafos) {
Transform transform = fac.newTransform(trafo.getAlgorithm(), (TransformParameterSpec) trafo.getParameterSpec());
transforms.add(transform);
LOG.debug("Transform method: {}", trafo.getAlgorithm());
}
return transforms;
}
protected boolean isEnveloped() {
return getConfiguration().getParentLocalName() != null;
}
private boolean containsEnvelopedTransform(List<AlgorithmMethod> configuredTrafos) {
for (AlgorithmMethod m : configuredTrafos) {
if (Transform.ENVELOPED.equals(m.getAlgorithm())) {
return true;
}
}
return false;
}
protected String getDigestAlgorithmUri() throws XmlSignatureException {
String result = getConfiguration().getDigestAlgorithm();
if (result == null) {
String signatureAlgorithm = getConfiguration().getSignatureAlgorithm();
if (signatureAlgorithm != null) {
if (signatureAlgorithm.contains(SHA1)) {
result = DigestMethod.SHA1;
} else if (signatureAlgorithm.contains(SHA256)) {
result = DigestMethod.SHA256;
} else if (signatureAlgorithm.contains(SHA384)) {
result = HTTP_WWW_W3_ORG_2001_04_XMLDSIG_MORE_SHA384;
} else if (signatureAlgorithm.contains(SHA512)) {
result = DigestMethod.SHA512;
}
}
}
if (result != null) {
LOG.debug("Digest algorithm: {}", result);
return result;
}
throw new XmlSignatureException(
"Digest algorithm missing for XML signature generation. Specify the digest algorithm in the configuration.");
}
protected Reference createKeyInfoReference(XMLSignatureFactory fac, String keyInfoId, String digestAlgorithm) throws Exception { //NOPMD
if (keyInfoId == null) {
return null;
}
if (getConfiguration().getAddKeyInfoReference() == null) {
return null;
}
if (!getConfiguration().getAddKeyInfoReference()) {
return null;
}
LOG.debug("Creating reference to key info element with Id: {}", keyInfoId);
List<Transform> transforms = new ArrayList<Transform>(1);
Transform transform = fac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);
transforms.add(transform);
return fac.newReference("#" + keyInfoId, fac.newDigestMethod(digestAlgorithm, null), transforms, null, null);
}
private String getKeyInfoId(KeyInfo keyInfo) throws Exception { //NOPMD
if (keyInfo == null) {
return null;
}
return keyInfo.getId();
}
private static class InputBuilder {
private XMLSignatureFactory signatureFactory;
private String signatureAlgorithm;
private Node parent;
private Node messageBodyNode;
private Message message;
private KeyInfo keyInfo;
private String contentDigestAlgorithm;
private String signatureId;
public InputBuilder signatureFactory(XMLSignatureFactory signatureFactory) {
this.signatureFactory = signatureFactory;
return this;
}
public InputBuilder signatureAlgorithm(String signatureAlgorithm) {
this.signatureAlgorithm = signatureAlgorithm;
return this;
}
public InputBuilder parent(Node parent) {
this.parent = parent;
return this;
}
public InputBuilder messageBodyNode(Node messageBodyNode) {
this.messageBodyNode = messageBodyNode;
return this;
}
public InputBuilder message(Message message) {
this.message = message;
return this;
}
public InputBuilder keyInfo(KeyInfo keyInfo) {
this.keyInfo = keyInfo;
return this;
}
public InputBuilder contentDigestAlgorithm(String contentDigestAlgorithm) {
this.contentDigestAlgorithm = contentDigestAlgorithm;
return this;
}
public InputBuilder signatureId(String signatureId) {
this.signatureId = signatureId;
return this;
}
public XmlSignatureProperties.Input build() {
return new XmlSignatureProperties.Input() {
@Override
public XMLSignatureFactory getSignatureFactory() {
return signatureFactory;
}
@Override
public String getSignatureAlgorithm() {
return signatureAlgorithm;
}
@Override
public Node getParent() {
return parent;
}
@Override
public Node getMessageBodyNode() {
return messageBodyNode;
}
@Override
public Message getMessage() {
return message;
}
@Override
public KeyInfo getKeyInfo() {
return keyInfo;
}
@Override
public String getContentDigestAlgorithm() {
return contentDigestAlgorithm;
}
@Override
public String getSignatureId() {
return signatureId;
}
};
}
}
}