Skip to content
Open
Show file tree
Hide file tree
Changes from all 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