Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

exports org.apache.jcp.xml.dsig.internal.dom;
exports org.apache.xml.security;
exports org.apache.xml.security.extension;
exports org.apache.xml.security.extension.xades;
exports org.apache.xml.security.algorithms;
exports org.apache.xml.security.algorithms.implementations;
exports org.apache.xml.security.c14n;
Expand Down
81 changes: 61 additions & 20 deletions src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package org.apache.jcp.xml.dsig.internal.dom;

import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.List;

import javax.xml.XMLConstants;
Expand All @@ -39,6 +40,7 @@
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* Useful static DOM utility methods.
Expand All @@ -49,6 +51,9 @@ public final class DOMUtils {
// class cannot be instantiated
private DOMUtils() {}

/** Attribute names treated as XML ID attributes when scanning for ID declarations. */
private static final List<String> ID_ATTRIBUTE_NAMES = Arrays.asList("Id", "ID", "id");

/**
* Returns the owner document of the specified node.
*
Expand Down Expand Up @@ -92,7 +97,7 @@ public static Element createElement(Document doc, String tag,
String nsURI, String prefix)
{
String qName = (prefix == null || prefix.length() == 0)
? tag : prefix + ":" + tag;
? tag : prefix + ":" + tag;
return doc.createElementNS(nsURI, qName);
}

Expand Down Expand Up @@ -158,23 +163,23 @@ public static Element getFirstChildElement(Node node) {
* equal to {@code localName}
*/
public static Element getFirstChildElement(Node node, String localName, String namespaceURI)
throws MarshalException
throws MarshalException
{
return verifyElement(getFirstChildElement(node), localName, namespaceURI);
}

private static Element verifyElement(Element elem, String localName, String namespaceURI)
throws MarshalException
throws MarshalException
{
if (elem == null) {
throw new MarshalException("Missing " + localName + " element");
}
String name = elem.getLocalName();
String namespace = elem.getNamespaceURI();
if (!name.equals(localName) || namespace == null && namespaceURI != null
|| namespace != null && !namespace.equals(namespaceURI)) {
|| namespace != null && !namespace.equals(namespaceURI)) {
throw new MarshalException("Invalid element name: " +
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);
}
return elem;
}
Expand Down Expand Up @@ -225,7 +230,7 @@ public static Element getNextSiblingElement(Node node) {
* equal to {@code localName}
*/
public static Element getNextSiblingElement(Node node, String localName, String namespaceURI)
throws MarshalException
throws MarshalException
{
return verifyElement(getNextSiblingElement(node), localName, namespaceURI);
}
Expand Down Expand Up @@ -282,7 +287,7 @@ public static <N> String getIdAttributeValue(Element elem, String name) {
public static String getNSPrefix(XMLCryptoContext context, String nsURI) {
if (context != null) {
return context.getNamespacePrefix
(nsURI, context.getDefaultNamespacePrefix());
(nsURI, context.getDefaultNamespacePrefix());
} else {
return null;
}
Expand Down Expand Up @@ -335,29 +340,29 @@ public static void appendChild(Node parent, Node child) {
}

public static boolean paramsEqual(AlgorithmParameterSpec spec1,
AlgorithmParameterSpec spec2) {
AlgorithmParameterSpec spec2) {
if (spec1 == spec2) {
return true;
}
if (spec1 instanceof XPathFilter2ParameterSpec &&
spec2 instanceof XPathFilter2ParameterSpec) {
spec2 instanceof XPathFilter2ParameterSpec) {
return paramsEqual((XPathFilter2ParameterSpec)spec1,
(XPathFilter2ParameterSpec)spec2);
(XPathFilter2ParameterSpec)spec2);
}
if (spec1 instanceof ExcC14NParameterSpec &&
spec2 instanceof ExcC14NParameterSpec) {
spec2 instanceof ExcC14NParameterSpec) {
return paramsEqual((ExcC14NParameterSpec) spec1,
(ExcC14NParameterSpec)spec2);
(ExcC14NParameterSpec)spec2);
}
if (spec1 instanceof XPathFilterParameterSpec &&
spec2 instanceof XPathFilterParameterSpec) {
spec2 instanceof XPathFilterParameterSpec) {
return paramsEqual((XPathFilterParameterSpec)spec1,
(XPathFilterParameterSpec)spec2);
(XPathFilterParameterSpec)spec2);
}
if (spec1 instanceof XSLTTransformParameterSpec &&
spec2 instanceof XSLTTransformParameterSpec) {
spec2 instanceof XSLTTransformParameterSpec) {
return paramsEqual((XSLTTransformParameterSpec)spec1,
(XSLTTransformParameterSpec)spec2);
(XSLTTransformParameterSpec)spec2);
}
return false;
}
Expand All @@ -377,8 +382,8 @@ private static boolean paramsEqual(XPathFilter2ParameterSpec spec1,
XPathType type = types.get(i);
XPathType otype = otypes.get(i);
if (!type.getExpression().equals(otype.getExpression()) ||
!type.getNamespaceMap().equals(otype.getNamespaceMap()) ||
type.getFilter() != otype.getFilter()) {
!type.getNamespaceMap().equals(otype.getNamespaceMap()) ||
type.getFilter() != otype.getFilter()) {
return false;
}
}
Expand Down Expand Up @@ -407,10 +412,10 @@ private static boolean paramsEqual(XSLTTransformParameterSpec spec1,
return false;
}
Node ostylesheetElem =
((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode();
((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode();
XMLStructure stylesheet = spec1.getStylesheet();
Node stylesheetElem =
((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode();
((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode();
return nodesEqual(stylesheetElem, ostylesheetElem);
}

Expand All @@ -422,4 +427,40 @@ public static boolean isNamespace(Node node)
}
return false;
}

/**
* Recursively walks the DOM tree rooted at {@code node} and calls
* {@link Element#setIdAttribute(String, boolean)} for every attribute whose local name
* is one of {@code Id}, {@code ID}, or {@code id}. This is required so that
* {@link Document#getElementById} correctly resolves same-document ID references in
* XAdES-generated structures.
*
* @param node the root node to start from
*/
public static void setIdFlagToIdAttributes(Node node) {
setIdFlagToIdAttributes(node, ID_ATTRIBUTE_NAMES);
}

/**
* Recursively walks the DOM tree rooted at {@code node} and calls
* {@link Element#setIdAttribute(String, boolean)} for every attribute whose local name
* is in {@code idAttributeNames}.
*
* @param node the root node to start from
* @param idAttributeNames the list of attribute local names to treat as Id attributes
*/
public static void setIdFlagToIdAttributes(Node node, List<String> idAttributeNames) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
for (String idName : idAttributeNames) {
if (element.hasAttribute(idName)) {
element.setIdAttribute(idName, true);
}
}
NodeList children = element.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
setIdFlagToIdAttributes(children.item(i), idAttributeNames);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* 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.xml.security.extension;

import org.apache.xml.security.signature.XMLSignatureException;

/**
* Thrown by a {@link SignatureProcessor} when it cannot complete its processing
* and the signing operation must be aborted.
*
* <p>Extends {@link XMLSignatureException} so callers that already handle the
* standard library exception hierarchy will catch this automatically.
*/
public class SignatureExtensionException extends XMLSignatureException {

private static final long serialVersionUID = 1L;

private final String detailMessage;

/**
* @param message human-readable description of the failure
*/
public SignatureExtensionException(String message) {
super(message);
this.detailMessage = message;
}

/**
* @param message human-readable description of the failure
* @param cause the underlying exception that triggered this failure
*/
public SignatureExtensionException(String message, Throwable cause) {
super(message);
this.detailMessage = message;
if (cause != null) {
initCause(cause);
}
}

@Override
public String getMessage() {
return detailMessage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* 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.xml.security.extension;

import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;

/**
* Extension point for pluggable pre- and post-signature processing hooks in
* the DOM-based XML Signature implementation.
*
* <p>Instances are registered on an {@link XMLSignature} via
* {@link XMLSignature#addPreProcessor(SignatureProcessor)} or
* {@link XMLSignature#addPostProcessor(SignatureProcessor)}.
*
* <ul>
* <li><b>Pre-processors</b> are invoked before digest values are computed on
* the {@code ds:SignedInfo} references. A pre-processor may therefore add
* XML content (e.g., XAdES {@code QualifyingProperties}) that will be
* covered by the signature digest.</li>
* <li><b>Post-processors</b> are invoked after the {@code ds:SignatureValue}
* element has been populated with the completed signature bytes. A
* post-processor may read the final signature value, for example to
* request a signature-timestamp token for XAdES-T.</li>
* </ul>
*
* <p>If a processor throws {@link XMLSignatureException} the signing operation
* is aborted and the exception is propagated to the caller of
* {@link XMLSignature#sign(java.security.Key)}.
*
*/
public interface SignatureProcessor {

/**
* Called during the {@link XMLSignature#sign(java.security.Key)} lifecycle.
*
* @param signature the signature being created; never {@code null}
* @throws XMLSignatureException if processing fails and signing must be aborted
*/
void processSignature(XMLSignature signature) throws XMLSignatureException;
}
Loading