feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,125 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DigesterOutputStream.java, v 1.5 2005/12/20 20:02:39 mullan Exp $
*/
package org.jcp.xml.dsig.internal;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStream;
/**
* This class has been modified slightly to use java.security.MessageDigest
* objects as input, rather than
* com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm objects.
* It also optionally caches the input bytes.
*
*/
public class DigesterOutputStream extends OutputStream {
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DigesterOutputStream.class);
private final boolean buffer;
private UnsyncByteArrayOutputStream bos;
private final MessageDigest md;
/**
* Creates a DigesterOutputStream.
*
* @param md the MessageDigest
*/
public DigesterOutputStream(MessageDigest md) {
this(md, false);
}
/**
* Creates a DigesterOutputStream.
*
* @param md the MessageDigest
* @param buffer if true, caches the input bytes
*/
public DigesterOutputStream(MessageDigest md, boolean buffer) {
this.md = md;
this.buffer = buffer;
if (buffer) {
bos = new UnsyncByteArrayOutputStream();
}
}
public void write(int input) {
if (buffer) {
bos.write(input);
}
md.update((byte)input);
}
@Override
public void write(byte[] input, int offset, int len) {
if (buffer) {
bos.write(input, offset, len);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Pre-digested input:");
StringBuilder sb = new StringBuilder(len);
for (int i = offset; i < (offset + len); i++) {
sb.append((char)input[i]);
}
LOG.debug(sb.toString());
}
md.update(input, offset, len);
}
/**
* @return the digest value
*/
public byte[] getDigestValue() {
return md.digest();
}
/**
* @return an input stream containing the cached bytes, or
* null if not cached
*/
public InputStream getInputStream() {
if (buffer) {
return new ByteArrayInputStream(bos.toByteArray());
} else {
return null;
}
}
@Override
public void close() throws IOException {
if (buffer) {
bos.close();
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.jcp.xml.dsig.internal;
import java.io.ByteArrayOutputStream;
import javax.crypto.Mac;
/**
* Derived from Apache sources and changed to use Mac objects instead of
* com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm objects.
*
*
*/
public class MacOutputStream extends ByteArrayOutputStream {
private final Mac mac;
public MacOutputStream(Mac mac) {
this.mac = mac;
}
@Override
public void write(int arg0) {
super.write(arg0);
mac.update((byte) arg0);
}
@Override
public void write(byte[] arg0, int arg1, int arg2) {
super.write(arg0, arg1, arg2);
mac.update(arg0, arg1, arg2);
}
}

View File

@@ -0,0 +1,67 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: SignerOutputStream.java, v 1.2 2005/09/15 14:29:02 mullan Exp $
*/
package org.jcp.xml.dsig.internal;
import java.io.ByteArrayOutputStream;
import java.security.Signature;
import java.security.SignatureException;
/**
* Derived from Apache sources and changed to use java.security.Signature
* objects as input instead of
* com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm objects.
*
*/
public class SignerOutputStream extends ByteArrayOutputStream {
private final Signature sig;
public SignerOutputStream(Signature sig) {
this.sig = sig;
}
@Override
public void write(int arg0) {
super.write(arg0);
try {
sig.update((byte)arg0);
} catch (SignatureException e) {
throw new RuntimeException(e);
}
}
@Override
public void write(byte[] arg0, int arg1, int arg2) {
super.write(arg0, arg1, arg2);
try {
sig.update(arg0, arg1, arg2);
} catch (SignatureException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,219 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.jcp.xml.dsig.internal.dom;
import java.security.Key;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignContext;
import javax.xml.crypto.dsig.XMLValidateContext;
import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* An abstract class representing a SignatureMethod. Subclasses implement
* a specific XML DSig signature algorithm.
*/
abstract class AbstractDOMSignatureMethod extends DOMStructure
implements SignatureMethod {
// denotes the type of signature algorithm
enum Type { DSA, RSA, ECDSA, HMAC }
/**
* Verifies the passed-in signature with the specified key, using the
* underlying Signature or Mac algorithm.
*
* @param key the verification key
* @param si the SignedInfo
* @param sig the signature bytes to be verified
* @param context the XMLValidateContext
* @return {@code true} if the signature verified successfully,
* {@code false} if not
* @throws NullPointerException if {@code key}, {@code si} or
* {@code sig} are {@code null}
* @throws InvalidKeyException if the key is improperly encoded, of
* the wrong type, or parameters are missing, etc
* @throws SignatureException if an unexpected error occurs, such
* as the passed in signature is improperly encoded
* @throws XMLSignatureException if an unexpected error occurs
*/
abstract boolean verify(Key key, SignedInfo si, byte[] sig,
XMLValidateContext context)
throws InvalidKeyException, SignatureException, XMLSignatureException;
/**
* Signs the bytes with the specified key, using the underlying
* Signature or Mac algorithm.
*
* @param key the signing key
* @param si the SignedInfo
* @param context the XMLSignContext
* @return the signature
* @throws NullPointerException if {@code key} or
* {@code si} are {@code null}
* @throws InvalidKeyException if the key is improperly encoded, of
* the wrong type, or parameters are missing, etc
* @throws XMLSignatureException if an unexpected error occurs
*/
abstract byte[] sign(Key key, SignedInfo si, XMLSignContext context)
throws InvalidKeyException, XMLSignatureException;
/**
* Returns the java.security.Signature or javax.crypto.Mac standard
* algorithm name.
*/
abstract String getJCAAlgorithm();
/**
* Returns the type of signature algorithm.
*/
abstract Type getAlgorithmType();
/**
* This method invokes the {@link #marshalParams marshalParams}
* method to marshal any algorithm-specific parameters.
*/
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element smElem = DOMUtils.createElement(ownerDoc, "SignatureMethod",
XMLSignature.XMLNS, dsPrefix);
DOMUtils.setAttribute(smElem, "Algorithm", getAlgorithm());
if (getParameterSpec() != null) {
marshalParams(smElem, dsPrefix);
}
parent.appendChild(smElem);
}
/**
* Marshals the algorithm-specific parameters to an Element and
* appends it to the specified parent element. By default, this method
* throws an exception since most SignatureMethod algorithms do not have
* parameters. Subclasses should override it if they have parameters.
*
* @param parent the parent element to append the parameters to
* @param paramsPrefix the algorithm parameters prefix to use
* @throws MarshalException if the parameters cannot be marshalled
*/
void marshalParams(Element parent, String paramsPrefix)
throws MarshalException
{
throw new MarshalException("no parameters should " +
"be specified for the " + getAlgorithm() +
" SignatureMethod algorithm");
}
/**
* Unmarshals {@code SignatureMethodParameterSpec} from the specified
* {@code Element}. By default, this method throws an exception since
* most SignatureMethod algorithms do not have parameters. Subclasses should
* override it if they have parameters.
*
* @param paramsElem the {@code Element} holding the input params
* @return the algorithm-specific {@code SignatureMethodParameterSpec}
* @throws MarshalException if the parameters cannot be unmarshalled
*/
SignatureMethodParameterSpec unmarshalParams(Element paramsElem)
throws MarshalException
{
throw new MarshalException("no parameters should " +
"be specified for the " + getAlgorithm() +
" SignatureMethod algorithm");
}
/**
* Checks if the specified parameters are valid for this algorithm. By
* default, this method throws an exception if parameters are specified
* since most SignatureMethod algorithms do not have parameters. Subclasses
* should override it if they have parameters.
*
* @param params the algorithm-specific params (may be {@code null})
* @throws InvalidAlgorithmParameterException if the parameters are not
* appropriate for this signature method
*/
void checkParams(SignatureMethodParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null) {
throw new InvalidAlgorithmParameterException("no parameters " +
"should be specified for the " + getAlgorithm() +
" SignatureMethod algorithm");
}
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (!(o instanceof SignatureMethod)) {
return false;
}
SignatureMethod osm = (SignatureMethod)o;
return getAlgorithm().equals(osm.getAlgorithm()) &&
paramsEqual(osm.getParameterSpec());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + getAlgorithm().hashCode();
AlgorithmParameterSpec spec = getParameterSpec();
if (spec != null) {
result = 31 * result + spec.hashCode();
}
return result;
}
/**
* Returns true if parameters are equal; false otherwise.
*
* Subclasses should override this method to compare algorithm-specific
* parameters.
*/
boolean paramsEqual(AlgorithmParameterSpec spec)
{
return getParameterSpec() == spec;
}
}

View File

@@ -0,0 +1,274 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: ApacheCanonicalizer.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.security.spec.AlgorithmParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.util.Set;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.TransformException;
import javax.xml.crypto.dsig.TransformService;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import com.sun.org.apache.xml.internal.security.transforms.Transform;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public abstract class ApacheCanonicalizer extends TransformService {
static {
com.sun.org.apache.xml.internal.security.Init.init();
}
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(ApacheCanonicalizer.class);
protected Canonicalizer apacheCanonicalizer;
private Transform apacheTransform;
protected String inclusiveNamespaces;
protected C14NMethodParameterSpec params;
protected Document ownerDoc;
protected Element transformElem;
public final AlgorithmParameterSpec getParameterSpec()
{
return params;
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException
{
if (context != null && !(context instanceof DOMCryptoContext)) {
throw new ClassCastException
("context must be of type DOMCryptoContext");
}
if (parent == null) {
throw new NullPointerException();
}
if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("parent must be of type DOMStructure");
}
transformElem = (Element)
((javax.xml.crypto.dom.DOMStructure)parent).getNode();
ownerDoc = DOMUtils.getOwnerDocument(transformElem);
}
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
if (context != null && !(context instanceof DOMCryptoContext)) {
throw new ClassCastException
("context must be of type DOMCryptoContext");
}
if (parent == null) {
throw new NullPointerException();
}
if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("parent must be of type DOMStructure");
}
transformElem = (Element)
((javax.xml.crypto.dom.DOMStructure)parent).getNode();
ownerDoc = DOMUtils.getOwnerDocument(transformElem);
}
public Data canonicalize(Data data, XMLCryptoContext xc)
throws TransformException
{
return canonicalize(data, xc, null);
}
public Data canonicalize(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
if (apacheCanonicalizer == null) {
try {
apacheCanonicalizer = Canonicalizer.getInstance(getAlgorithm());
boolean secVal = Utils.secureValidation(xc);
apacheCanonicalizer.setSecureValidation(secVal);
LOG.debug("Created canonicalizer for algorithm: {}", getAlgorithm());
} catch (InvalidCanonicalizerException ice) {
throw new TransformException
("Couldn't find Canonicalizer for: " + getAlgorithm() +
": " + ice.getMessage(), ice);
}
}
if (os != null) {
apacheCanonicalizer.setWriter(os);
} else {
apacheCanonicalizer.setWriter(new ByteArrayOutputStream());
}
try {
Set<Node> nodeSet = null;
if (data instanceof ApacheData) {
XMLSignatureInput in =
((ApacheData)data).getXMLSignatureInput();
if (in.isElement()) {
if (inclusiveNamespaces != null) {
return new OctetStreamData(new ByteArrayInputStream
(apacheCanonicalizer.canonicalizeSubtree
(in.getSubNode(), inclusiveNamespaces)));
} else {
return new OctetStreamData(new ByteArrayInputStream
(apacheCanonicalizer.canonicalizeSubtree
(in.getSubNode())));
}
} else if (in.isNodeSet()) {
nodeSet = in.getNodeSet();
} else {
return new OctetStreamData(new ByteArrayInputStream(
apacheCanonicalizer.canonicalize(
Utils.readBytesFromStream(in.getOctetStream()))));
}
} else if (data instanceof DOMSubTreeData) {
DOMSubTreeData subTree = (DOMSubTreeData)data;
if (inclusiveNamespaces != null) {
return new OctetStreamData(new ByteArrayInputStream
(apacheCanonicalizer.canonicalizeSubtree
(subTree.getRoot(), inclusiveNamespaces)));
} else {
return new OctetStreamData(new ByteArrayInputStream
(apacheCanonicalizer.canonicalizeSubtree
(subTree.getRoot())));
}
} else if (data instanceof NodeSetData) {
NodeSetData nsd = (NodeSetData)data;
// convert Iterator to Set
@SuppressWarnings("unchecked")
Set<Node> ns = Utils.toNodeSet(nsd.iterator());
nodeSet = ns;
LOG.debug("Canonicalizing {} nodes", nodeSet.size());
} else {
return new OctetStreamData(new ByteArrayInputStream(
apacheCanonicalizer.canonicalize(
Utils.readBytesFromStream(
((OctetStreamData)data).getOctetStream()))));
}
if (inclusiveNamespaces != null) {
return new OctetStreamData(new ByteArrayInputStream(
apacheCanonicalizer.canonicalizeXPathNodeSet
(nodeSet, inclusiveNamespaces)));
} else {
return new OctetStreamData(new ByteArrayInputStream(
apacheCanonicalizer.canonicalizeXPathNodeSet(nodeSet)));
}
} catch (Exception e) {
throw new TransformException(e);
}
}
public Data transform(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
if (data == null) {
throw new NullPointerException("data must not be null");
}
if (os == null) {
throw new NullPointerException("output stream must not be null");
}
if (ownerDoc == null) {
throw new TransformException("transform must be marshalled");
}
if (apacheTransform == null) {
try {
apacheTransform =
new Transform(ownerDoc, getAlgorithm(), transformElem.getChildNodes());
apacheTransform.setElement(transformElem, xc.getBaseURI());
boolean secVal = Utils.secureValidation(xc);
apacheTransform.setSecureValidation(secVal);
LOG.debug("Created transform for algorithm: {}", getAlgorithm());
} catch (Exception ex) {
throw new TransformException
("Couldn't find Transform for: " + getAlgorithm(), ex);
}
}
XMLSignatureInput in;
if (data instanceof ApacheData) {
LOG.debug("ApacheData = true");
in = ((ApacheData)data).getXMLSignatureInput();
} else if (data instanceof NodeSetData) {
LOG.debug("isNodeSet() = true");
if (data instanceof DOMSubTreeData) {
DOMSubTreeData subTree = (DOMSubTreeData)data;
in = new XMLSignatureInput(subTree.getRoot());
in.setExcludeComments(subTree.excludeComments());
} else {
@SuppressWarnings("unchecked")
Set<Node> nodeSet =
Utils.toNodeSet(((NodeSetData)data).iterator());
in = new XMLSignatureInput(nodeSet);
}
} else {
LOG.debug("isNodeSet() = false");
try {
in = new XMLSignatureInput
(((OctetStreamData)data).getOctetStream());
} catch (Exception ex) {
throw new TransformException(ex);
}
}
boolean secVal = Utils.secureValidation(xc);
in.setSecureValidation(secVal);
try {
in = apacheTransform.performTransform(in, os);
if (!in.isNodeSet() && !in.isElement()) {
return null;
}
if (in.isOctetStream()) {
return new ApacheOctetStreamData(in);
} else {
return new ApacheNodeSetData(in);
}
} catch (Exception ex) {
throw new TransformException(ex);
}
}
public final boolean isFeatureSupported(String feature) {
if (feature == null) {
throw new NullPointerException();
} else {
return false;
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: ApacheData.java 1788465 2017-03-24 15:10:51Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.Data;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
/**
* XMLSignatureInput Data wrapper.
*
*/
public interface ApacheData extends Data {
/**
* Returns the XMLSignatureInput.
*/
XMLSignatureInput getXMLSignatureInput();
}

View File

@@ -0,0 +1,94 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: ApacheNodeSetData.java 1496478 2013-06-25 14:01:16Z mullan $
*/
package org.jcp.xml.dsig.internal.dom;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.xml.crypto.NodeSetData;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.signature.NodeFilter;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
public class ApacheNodeSetData implements ApacheData, NodeSetData {
private XMLSignatureInput xi;
public ApacheNodeSetData(XMLSignatureInput xi) {
this.xi = xi;
}
public Iterator<Node> iterator() {
// If nodefilters are set, must execute them first to create node-set
if (xi.getNodeFilters() != null && !xi.getNodeFilters().isEmpty()) {
return Collections.unmodifiableSet
(getNodeSet(xi.getNodeFilters())).iterator();
}
try {
return Collections.unmodifiableSet(xi.getNodeSet()).iterator();
} catch (Exception e) {
// should not occur
throw new RuntimeException
("unrecoverable error retrieving nodeset", e);
}
}
public XMLSignatureInput getXMLSignatureInput() {
return xi;
}
private Set<Node> getNodeSet(List<NodeFilter> nodeFilters) {
if (xi.isNeedsToBeExpanded()) {
XMLUtils.circumventBug2650
(XMLUtils.getOwnerDocument(xi.getSubNode()));
}
Set<Node> inputSet = new LinkedHashSet<Node>();
XMLUtils.getSet(xi.getSubNode(), inputSet,
null, !xi.isExcludeComments());
Set<Node> nodeSet = new LinkedHashSet<Node>();
for (Node currentNode : inputSet) {
Iterator<NodeFilter> it = nodeFilters.iterator();
boolean skipNode = false;
while (it.hasNext() && !skipNode) {
NodeFilter nf = it.next();
if (nf.isNodeInclude(currentNode) != 1) {
skipNode = true;
}
}
if (!skipNode) {
nodeSet.add(currentNode);
}
}
return nodeSet;
}
}

View File

@@ -0,0 +1,51 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: ApacheOctetStreamData.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.IOException;
import javax.xml.crypto.OctetStreamData;
import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
public class ApacheOctetStreamData extends OctetStreamData
implements ApacheData {
private XMLSignatureInput xi;
public ApacheOctetStreamData(XMLSignatureInput xi)
throws CanonicalizationException, IOException
{
super(xi.getOctetStream(), xi.getSourceURI(), xi.getMIMEType());
this.xi = xi;
}
public XMLSignatureInput getXMLSignatureInput() {
return xi;
}
}

View File

@@ -0,0 +1,212 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: ApacheTransform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import com.sun.org.apache.xml.internal.security.transforms.Transform;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
/**
* This is a wrapper/glue class which invokes the Apache XML-Security
* Transform.
*
*/
public abstract class ApacheTransform extends TransformService {
static {
com.sun.org.apache.xml.internal.security.Init.init();
}
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(ApacheTransform.class);
private Transform apacheTransform;
protected Document ownerDoc;
protected Element transformElem;
protected TransformParameterSpec params;
@Override
public final AlgorithmParameterSpec getParameterSpec() {
return params;
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException
{
if (context != null && !(context instanceof DOMCryptoContext)) {
throw new ClassCastException
("context must be of type DOMCryptoContext");
}
if (parent == null) {
throw new NullPointerException();
}
if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("parent must be of type DOMStructure");
}
transformElem = (Element)
((javax.xml.crypto.dom.DOMStructure) parent).getNode();
ownerDoc = DOMUtils.getOwnerDocument(transformElem);
}
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
if (context != null && !(context instanceof DOMCryptoContext)) {
throw new ClassCastException
("context must be of type DOMCryptoContext");
}
if (parent == null) {
throw new NullPointerException();
}
if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("parent must be of type DOMStructure");
}
transformElem = (Element)
((javax.xml.crypto.dom.DOMStructure) parent).getNode();
ownerDoc = DOMUtils.getOwnerDocument(transformElem);
}
public Data transform(Data data, XMLCryptoContext xc)
throws TransformException
{
if (data == null) {
throw new NullPointerException("data must not be null");
}
return transformIt(data, xc, null);
}
public Data transform(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
if (data == null) {
throw new NullPointerException("data must not be null");
}
if (os == null) {
throw new NullPointerException("output stream must not be null");
}
return transformIt(data, xc, os);
}
private Data transformIt(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
if (ownerDoc == null) {
throw new TransformException("transform must be marshalled");
}
if (apacheTransform == null) {
try {
apacheTransform =
new Transform(ownerDoc, getAlgorithm(), transformElem.getChildNodes());
apacheTransform.setElement(transformElem, xc.getBaseURI());
boolean secVal = Utils.secureValidation(xc);
apacheTransform.setSecureValidation(secVal);
LOG.debug("Created transform for algorithm: {}", getAlgorithm());
} catch (Exception ex) {
throw new TransformException("Couldn't find Transform for: " +
getAlgorithm(), ex);
}
}
if (Utils.secureValidation(xc)) {
String algorithm = getAlgorithm();
if (Policy.restrictAlg(algorithm)) {
throw new TransformException(
"Transform " + algorithm + " is forbidden when secure validation is enabled"
);
}
}
XMLSignatureInput in;
if (data instanceof ApacheData) {
LOG.debug("ApacheData = true");
in = ((ApacheData)data).getXMLSignatureInput();
} else if (data instanceof NodeSetData) {
LOG.debug("isNodeSet() = true");
if (data instanceof DOMSubTreeData) {
LOG.debug("DOMSubTreeData = true");
DOMSubTreeData subTree = (DOMSubTreeData)data;
in = new XMLSignatureInput(subTree.getRoot());
in.setExcludeComments(subTree.excludeComments());
} else {
@SuppressWarnings("unchecked")
Set<Node> nodeSet =
Utils.toNodeSet(((NodeSetData)data).iterator());
in = new XMLSignatureInput(nodeSet);
}
} else {
LOG.debug("isNodeSet() = false");
try {
in = new XMLSignatureInput
(((OctetStreamData)data).getOctetStream());
} catch (Exception ex) {
throw new TransformException(ex);
}
}
boolean secVal = Utils.secureValidation(xc);
in.setSecureValidation(secVal);
try {
if (os != null) {
in = apacheTransform.performTransform(in, os);
if (!in.isNodeSet() && !in.isElement()) {
return null;
}
} else {
in = apacheTransform.performTransform(in);
}
if (in.isOctetStream()) {
return new ApacheOctetStreamData(in);
} else {
return new ApacheNodeSetData(in);
}
} catch (Exception ex) {
throw new TransformException(ex);
}
}
public final boolean isFeatureSupported(String feature) {
if (feature == null) {
throw new NullPointerException();
} else {
return false;
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMBase64Transform.java 1788465 2017-03-24 15:10:51Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.security.InvalidAlgorithmParameterException;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
/**
* DOM-based implementation of Base64 Encoding Transform.
* (Uses Apache XML-Sec Transform implementation)
*
*/
public final class DOMBase64Transform extends ApacheTransform {
@Override
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params != null) {
throw new InvalidAlgorithmParameterException("params must be null");
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id$
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
/**
* DOM-based implementation of CanonicalizationMethod for Canonical XML 1.1
* (with or without comments). Uses Apache XML-Sec Canonicalizer.
*
*/
public final class DOMCanonicalXMLC14N11Method extends ApacheCanonicalizer {
public static final String C14N_11 = "http://www.w3.org/2006/12/xml-c14n11";
public static final String C14N_11_WITH_COMMENTS
= "http://www.w3.org/2006/12/xml-c14n11#WithComments";
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params != null) {
throw new InvalidAlgorithmParameterException("no parameters " +
"should be specified for Canonical XML 1.1 algorithm");
}
}
public Data transform(Data data, XMLCryptoContext xc)
throws TransformException {
// ignore comments if dereferencing same-document URI that requires
// you to omit comments, even if the Transform says otherwise -
// this is to be compliant with section 4.3.3.3 of W3C Rec.
if (data instanceof DOMSubTreeData) {
DOMSubTreeData subTree = (DOMSubTreeData) data;
if (subTree.excludeComments()) {
try {
apacheCanonicalizer = Canonicalizer.getInstance(C14N_11);
boolean secVal = Utils.secureValidation(xc);
apacheCanonicalizer.setSecureValidation(secVal);
} catch (InvalidCanonicalizerException ice) {
throw new TransformException
("Couldn't find Canonicalizer for: " +
C14N_11 + ": " + ice.getMessage(), ice);
}
}
}
return canonicalize(data, xc);
}
}

View File

@@ -0,0 +1,80 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMCanonicalXMLC14NMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
/**
* DOM-based implementation of CanonicalizationMethod for Canonical XML
* (with or without comments). Uses Apache XML-Sec Canonicalizer.
*
*/
public final class DOMCanonicalXMLC14NMethod extends ApacheCanonicalizer {
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params != null) {
throw new InvalidAlgorithmParameterException("no parameters " +
"should be specified for Canonical XML C14N algorithm");
}
}
public Data transform(Data data, XMLCryptoContext xc)
throws TransformException {
// ignore comments if dereferencing same-document URI that requires
// you to omit comments, even if the Transform says otherwise -
// this is to be compliant with section 4.3.3.3 of W3C Rec.
if (data instanceof DOMSubTreeData) {
DOMSubTreeData subTree = (DOMSubTreeData) data;
if (subTree.excludeComments()) {
try {
apacheCanonicalizer = Canonicalizer.getInstance
(CanonicalizationMethod.INCLUSIVE);
boolean secVal = Utils.secureValidation(xc);
apacheCanonicalizer.setSecureValidation(secVal);
} catch (InvalidCanonicalizerException ice) {
throw new TransformException
("Couldn't find Canonicalizer for: " +
CanonicalizationMethod.INCLUSIVE + ": " +
ice.getMessage(), ice);
}
}
}
return canonicalize(data, xc);
}
}

View File

@@ -0,0 +1,148 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMCanonicalizationMethod.java 1788465 2017-03-24 15:10:51Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.Provider;
import java.security.spec.AlgorithmParameterSpec;
import org.w3c.dom.Element;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
/**
* DOM-based abstract implementation of CanonicalizationMethod.
*
*/
public class DOMCanonicalizationMethod extends DOMTransform
implements CanonicalizationMethod {
/**
* Creates a {@code DOMCanonicalizationMethod}.
*
* @param spi TransformService
*/
public DOMCanonicalizationMethod(TransformService spi)
throws InvalidAlgorithmParameterException
{
super(spi);
if (!(spi instanceof ApacheCanonicalizer) && !isC14Nalg(spi.getAlgorithm())) {
throw new InvalidAlgorithmParameterException("Illegal CanonicalizationMethod");
}
}
/**
* Creates a {@code DOMCanonicalizationMethod} from an element. It unmarshals any
* algorithm-specific input parameters.
*
* @param cmElem a CanonicalizationMethod element
*/
public DOMCanonicalizationMethod(Element cmElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
super(cmElem, context, provider);
if (!(spi instanceof ApacheCanonicalizer) && !isC14Nalg(spi.getAlgorithm())) {
throw new MarshalException("Illegal CanonicalizationMethod");
}
}
/**
* Canonicalizes the specified data using the underlying canonicalization
* algorithm. This is a convenience method that is equivalent to invoking
* the {@link #transform transform} method.
*
* @param data the data to be canonicalized
* @param xc the {@code XMLCryptoContext} containing
* additional context (may be {@code null} if not applicable)
* @return the canonicalized data
* @throws NullPointerException if {@code data} is {@code null}
* @throws TransformException if an unexpected error occurs while
* canonicalizing the data
*/
public Data canonicalize(Data data, XMLCryptoContext xc)
throws TransformException
{
return transform(data, xc);
}
public Data canonicalize(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
return transform(data, xc, os);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CanonicalizationMethod)) {
return false;
}
CanonicalizationMethod ocm = (CanonicalizationMethod)o;
return getAlgorithm().equals(ocm.getAlgorithm()) &&
DOMUtils.paramsEqual(getParameterSpec(), ocm.getParameterSpec());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + getAlgorithm().hashCode();
AlgorithmParameterSpec spec = getParameterSpec();
if (spec != null) {
result = 31 * result + spec.hashCode();
}
return result;
}
private static boolean isC14Nalg(String alg) {
return isInclusiveC14Nalg(alg) || isExclusiveC14Nalg(alg) || isC14N11alg(alg);
}
private static boolean isInclusiveC14Nalg(String alg) {
return alg.equals(CanonicalizationMethod.INCLUSIVE)
|| alg.equals(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS);
}
private static boolean isExclusiveC14Nalg(String alg) {
return alg.equals(CanonicalizationMethod.EXCLUSIVE)
|| alg.equals(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS);
}
private static boolean isC14N11alg(String alg) {
return alg.equals(DOMCanonicalXMLC14N11Method.C14N_11)
|| alg.equals(DOMCanonicalXMLC14N11Method.C14N_11_WITH_COMMENTS);
}
}

View File

@@ -0,0 +1,105 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id$
*/
package org.jcp.xml.dsig.internal.dom;
import java.math.BigInteger;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
/**
* A DOM-based representation of the XML {@code CryptoBinary} simple type
* as defined in the W3C specification for XML-Signature Syntax and Processing.
* The XML Schema Definition is defined as:
*
* <pre>{@code
* <simpleType name="CryptoBinary">
* <restriction base = "base64Binary">
* </restriction>
* </simpleType>
* }</pre>
*
* @author Sean Mullan
*/
public final class DOMCryptoBinary extends DOMStructure {
private final BigInteger bigNum;
private final String value;
/**
* Create a {@code DOMCryptoBinary} instance from the specified
* {@code BigInteger}
*
* @param bigNum the arbitrary-length integer
* @throws NullPointerException if {@code bigNum} is {@code null}
*/
public DOMCryptoBinary(BigInteger bigNum) {
if (bigNum == null) {
throw new NullPointerException("bigNum is null");
}
this.bigNum = bigNum;
// convert to bitstring
byte[] bytes = XMLUtils.getBytes(bigNum, bigNum.bitLength());
value = XMLUtils.encodeToString(bytes);
}
/**
* Creates a {@code DOMCryptoBinary} from a node.
*
* @param cbNode a CryptoBinary text node
* @throws MarshalException if value cannot be decoded (invalid format)
*/
public DOMCryptoBinary(Node cbNode) throws MarshalException {
value = cbNode.getNodeValue();
try {
bigNum = new BigInteger(1, XMLUtils.decode(((Text) cbNode).getData()));
} catch (Exception ex) {
throw new MarshalException(ex);
}
}
/**
* Returns the {@code BigInteger} that this object contains.
*
* @return the {@code BigInteger} that this object contains
*/
public BigInteger getBigNum() {
return bigNum;
}
@Override
public void marshal(Node parent, String prefix, DOMCryptoContext context)
throws MarshalException {
parent.appendChild
(DOMUtils.getOwnerDocument(parent).createTextNode(value));
}
}

View File

@@ -0,0 +1,328 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMDigestMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based abstract implementation of DigestMethod.
*
*/
public abstract class DOMDigestMethod extends DOMStructure
implements DigestMethod {
static final String SHA224 =
"http://www.w3.org/2001/04/xmldsig-more#sha224"; // see RFC 4051
static final String SHA384 =
"http://www.w3.org/2001/04/xmldsig-more#sha384"; // see RFC 4051
private DigestMethodParameterSpec params;
/**
* Creates a {@code DOMDigestMethod}.
*
* @param params the algorithm-specific params (may be {@code null})
* @throws InvalidAlgorithmParameterException if the parameters are not
* appropriate for this digest method
*/
DOMDigestMethod(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null && !(params instanceof DigestMethodParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type DigestMethodParameterSpec");
}
checkParams((DigestMethodParameterSpec)params);
this.params = (DigestMethodParameterSpec)params;
}
/**
* Creates a {@code DOMDigestMethod} from an element. This constructor
* invokes the abstract {@link #unmarshalParams unmarshalParams} method to
* unmarshal any algorithm-specific input parameters.
*
* @param dmElem a DigestMethod element
*/
DOMDigestMethod(Element dmElem) throws MarshalException {
Element paramsElem = DOMUtils.getFirstChildElement(dmElem);
if (paramsElem != null) {
params = unmarshalParams(paramsElem);
}
try {
checkParams(params);
} catch (InvalidAlgorithmParameterException iape) {
throw new MarshalException(iape);
}
}
static DigestMethod unmarshal(Element dmElem) throws MarshalException {
String alg = DOMUtils.getAttributeValue(dmElem, "Algorithm");
if (alg.equals(DigestMethod.SHA1)) {
return new SHA1(dmElem);
} else if (alg.equals(SHA224)) {
return new SHA224(dmElem);
} else if (alg.equals(DigestMethod.SHA256)) {
return new SHA256(dmElem);
} else if (alg.equals(SHA384)) {
return new SHA384(dmElem);
} else if (alg.equals(DigestMethod.SHA512)) {
return new SHA512(dmElem);
} else if (alg.equals(DigestMethod.RIPEMD160)) {
return new RIPEMD160(dmElem);
} else {
throw new MarshalException("unsupported DigestMethod algorithm: " +
alg);
}
}
/**
* Checks if the specified parameters are valid for this algorithm. By
* default, this method throws an exception if parameters are specified
* since most DigestMethod algorithms do not have parameters. Subclasses
* should override it if they have parameters.
*
* @param params the algorithm-specific params (may be {@code null})
* @throws InvalidAlgorithmParameterException if the parameters are not
* appropriate for this digest method
*/
void checkParams(DigestMethodParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null) {
throw new InvalidAlgorithmParameterException("no parameters " +
"should be specified for the " + getMessageDigestAlgorithm() +
" DigestMethod algorithm");
}
}
public final AlgorithmParameterSpec getParameterSpec() {
return params;
}
/**
* Unmarshals {@code DigestMethodParameterSpec} from the specified
* {@code Element}. By default, this method throws an exception since
* most DigestMethod algorithms do not have parameters. Subclasses should
* override it if they have parameters.
*
* @param paramsElem the {@code Element} holding the input params
* @return the algorithm-specific {@code DigestMethodParameterSpec}
* @throws MarshalException if the parameters cannot be unmarshalled
*/
DigestMethodParameterSpec unmarshalParams(Element paramsElem)
throws MarshalException
{
throw new MarshalException("no parameters should " +
"be specified for the " +
getMessageDigestAlgorithm() +
" DigestMethod algorithm");
}
/**
* This method invokes the abstract {@link #marshalParams marshalParams}
* method to marshal any algorithm-specific parameters.
*/
@Override
public void marshal(Node parent, String prefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element dmElem = DOMUtils.createElement(ownerDoc, "DigestMethod",
XMLSignature.XMLNS, prefix);
DOMUtils.setAttribute(dmElem, "Algorithm", getAlgorithm());
if (params != null) {
marshalParams(dmElem, prefix);
}
parent.appendChild(dmElem);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DigestMethod)) {
return false;
}
DigestMethod odm = (DigestMethod)o;
boolean paramsEqual = params == null ? odm.getParameterSpec() == null :
params.equals(odm.getParameterSpec());
return getAlgorithm().equals(odm.getAlgorithm()) && paramsEqual;
}
@Override
public int hashCode() {
int result = 17;
if (params != null) {
result = 31 * result + params.hashCode();
}
result = 31 * result + getAlgorithm().hashCode();
return result;
}
/**
* Marshals the algorithm-specific parameters to an Element and
* appends it to the specified parent element. By default, this method
* throws an exception since most DigestMethod algorithms do not have
* parameters. Subclasses should override it if they have parameters.
*
* @param parent the parent element to append the parameters to
* @param the namespace prefix to use
* @throws MarshalException if the parameters cannot be marshalled
*/
void marshalParams(Element parent, String prefix)
throws MarshalException
{
throw new MarshalException("no parameters should " +
"be specified for the " +
getMessageDigestAlgorithm() +
" DigestMethod algorithm");
}
/**
* Returns the MessageDigest standard algorithm name.
*/
abstract String getMessageDigestAlgorithm();
static final class SHA1 extends DOMDigestMethod {
SHA1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return DigestMethod.SHA1;
}
String getMessageDigestAlgorithm() {
return "SHA-1";
}
}
static final class SHA224 extends DOMDigestMethod {
SHA224(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA224(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return SHA224;
}
@Override
String getMessageDigestAlgorithm() {
return "SHA-224";
}
}
static final class SHA256 extends DOMDigestMethod {
SHA256(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return DigestMethod.SHA256;
}
String getMessageDigestAlgorithm() {
return "SHA-256";
}
}
static final class SHA384 extends DOMDigestMethod {
SHA384(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA384(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return SHA384;
}
String getMessageDigestAlgorithm() {
return "SHA-384";
}
}
static final class SHA512 extends DOMDigestMethod {
SHA512(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA512(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return DigestMethod.SHA512;
}
String getMessageDigestAlgorithm() {
return "SHA-512";
}
}
static final class RIPEMD160 extends DOMDigestMethod {
RIPEMD160(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
RIPEMD160(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return DigestMethod.RIPEMD160;
}
@Override
String getMessageDigestAlgorithm() {
return "RIPEMD160";
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMEnvelopedTransform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.security.InvalidAlgorithmParameterException;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
/**
* DOM-based implementation of Enveloped Signature Transform.
* (Uses Apache XML-Sec Transform implementation)
*
*/
public final class DOMEnvelopedTransform extends ApacheTransform {
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params != null) {
throw new InvalidAlgorithmParameterException("params must be null");
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMExcC14NMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.*;
import org.w3c.dom.Element;
import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
/**
* DOM-based implementation of CanonicalizationMethod for Exclusive
* Canonical XML algorithm (with or without comments).
* Uses Apache XML-Sec Canonicalizer.
*
*/
public final class DOMExcC14NMethod extends ApacheCanonicalizer {
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null) {
if (!(params instanceof ExcC14NParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type ExcC14NParameterSpec");
}
this.params = (C14NMethodParameterSpec)params;
}
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException
{
super.init(parent, context);
Element paramsElem = DOMUtils.getFirstChildElement(transformElem);
if (paramsElem == null) {
this.params = null;
this.inclusiveNamespaces = null;
return;
}
unmarshalParams(paramsElem);
}
private void unmarshalParams(Element paramsElem) {
String prefixListAttr = paramsElem.getAttributeNS(null, "PrefixList");
this.inclusiveNamespaces = prefixListAttr;
int begin = 0;
int end = prefixListAttr.indexOf(' ');
List<String> prefixList = new ArrayList<>();
while (end != -1) {
prefixList.add(prefixListAttr.substring(begin, end));
begin = end + 1;
end = prefixListAttr.indexOf(' ', begin);
}
if (begin <= prefixListAttr.length()) {
prefixList.add(prefixListAttr.substring(begin));
}
this.params = new ExcC14NParameterSpec(prefixList);
}
@SuppressWarnings("unchecked")
public List<String> getParameterSpecPrefixList(ExcC14NParameterSpec paramSpec) {
return paramSpec.getPrefixList();
}
@Override
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
super.marshalParams(parent, context);
AlgorithmParameterSpec spec = getParameterSpec();
if (spec == null) {
return;
}
String prefix = DOMUtils.getNSPrefix(context,
CanonicalizationMethod.EXCLUSIVE);
Element eElem = DOMUtils.createElement(ownerDoc,
"InclusiveNamespaces",
CanonicalizationMethod.EXCLUSIVE,
prefix);
if (prefix == null || prefix.length() == 0) {
eElem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns",
CanonicalizationMethod.EXCLUSIVE);
} else {
eElem.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns:" + prefix,
CanonicalizationMethod.EXCLUSIVE);
}
ExcC14NParameterSpec params = (ExcC14NParameterSpec)spec;
StringBuffer prefixListAttr = new StringBuffer("");
@SuppressWarnings("unchecked")
List<String> prefixList = getParameterSpecPrefixList(params);
for (int i = 0, size = prefixList.size(); i < size; i++) {
prefixListAttr.append(prefixList.get(i));
if (i < size - 1) {
prefixListAttr.append(" ");
}
}
DOMUtils.setAttribute(eElem, "PrefixList", prefixListAttr.toString());
this.inclusiveNamespaces = prefixListAttr.toString();
transformElem.appendChild(eElem);
}
public String getParamsNSURI() {
return CanonicalizationMethod.EXCLUSIVE;
}
public Data transform(Data data, XMLCryptoContext xc)
throws TransformException
{
// ignore comments if dereferencing same-document URI that require
// you to omit comments, even if the Transform says otherwise -
// this is to be compliant with section 4.3.3.3 of W3C Rec.
if (data instanceof DOMSubTreeData) {
DOMSubTreeData subTree = (DOMSubTreeData)data;
if (subTree.excludeComments()) {
try {
apacheCanonicalizer = Canonicalizer.getInstance
(CanonicalizationMethod.EXCLUSIVE);
boolean secVal = Utils.secureValidation(xc);
apacheCanonicalizer.setSecureValidation(secVal);
} catch (InvalidCanonicalizerException ice) {
throw new TransformException
("Couldn't find Canonicalizer for: " +
CanonicalizationMethod.EXCLUSIVE + ": " +
ice.getMessage(), ice);
}
}
}
return canonicalize(data, xc);
}
}

View File

@@ -0,0 +1,339 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMHMACSignatureMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.HMACParameterSpec;
import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.jcp.xml.dsig.internal.MacOutputStream;
/**
* DOM-based implementation of HMAC SignatureMethod.
*
*/
public abstract class DOMHMACSignatureMethod extends AbstractDOMSignatureMethod {
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMHMACSignatureMethod.class);
// see RFC 4051 for these algorithm definitions
static final String HMAC_SHA224 =
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha224";
static final String HMAC_SHA256 =
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256";
static final String HMAC_SHA384 =
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha384";
static final String HMAC_SHA512 =
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha512";
static final String HMAC_RIPEMD160 =
"http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160";
private Mac hmac;
private int outputLength;
private boolean outputLengthSet;
private SignatureMethodParameterSpec params;
/**
* Creates a {@code DOMHMACSignatureMethod} with the specified params
*
* @param params algorithm-specific parameters (may be {@code null})
* @throws InvalidAlgorithmParameterException if params are inappropriate
*/
DOMHMACSignatureMethod(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
{
checkParams((SignatureMethodParameterSpec)params);
this.params = (SignatureMethodParameterSpec)params;
}
/**
* Creates a {@code DOMHMACSignatureMethod} from an element.
*
* @param smElem a SignatureMethod element
*/
DOMHMACSignatureMethod(Element smElem) throws MarshalException {
Element paramsElem = DOMUtils.getFirstChildElement(smElem);
if (paramsElem != null) {
params = unmarshalParams(paramsElem);
}
try {
checkParams(params);
} catch (InvalidAlgorithmParameterException iape) {
throw new MarshalException(iape);
}
}
@Override
void checkParams(SignatureMethodParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null) {
if (!(params instanceof HMACParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type HMACParameterSpec");
}
outputLength = ((HMACParameterSpec)params).getOutputLength();
outputLengthSet = true;
LOG.debug("Setting outputLength from HMACParameterSpec to: {}", outputLength);
}
}
public final AlgorithmParameterSpec getParameterSpec() {
return params;
}
SignatureMethodParameterSpec unmarshalParams(Element paramsElem)
throws MarshalException
{
outputLength = Integer.parseInt(paramsElem.getFirstChild().getNodeValue());
outputLengthSet = true;
LOG.debug("unmarshalled outputLength: {}", outputLength);
return new HMACParameterSpec(outputLength);
}
void marshalParams(Element parent, String prefix)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element hmacElem = DOMUtils.createElement(ownerDoc, "HMACOutputLength",
XMLSignature.XMLNS, prefix);
hmacElem.appendChild(ownerDoc.createTextNode
(String.valueOf(outputLength)));
parent.appendChild(hmacElem);
}
boolean verify(Key key, SignedInfo si, byte[] sig,
XMLValidateContext context)
throws InvalidKeyException, SignatureException, XMLSignatureException
{
if (key == null || si == null || sig == null) {
throw new NullPointerException();
}
if (!(key instanceof SecretKey)) {
throw new InvalidKeyException("key must be SecretKey");
}
if (hmac == null) {
try {
hmac = Mac.getInstance(getJCAAlgorithm());
} catch (NoSuchAlgorithmException nsae) {
throw new XMLSignatureException(nsae);
}
}
if (outputLengthSet && outputLength < getDigestLength()) {
throw new XMLSignatureException
("HMACOutputLength must not be less than " + getDigestLength());
}
hmac.init(key);
((DOMSignedInfo)si).canonicalize(context, new MacOutputStream(hmac));
byte[] result = hmac.doFinal();
return MessageDigest.isEqual(sig, result);
}
byte[] sign(Key key, SignedInfo si, XMLSignContext context)
throws InvalidKeyException, XMLSignatureException
{
if (key == null || si == null) {
throw new NullPointerException();
}
if (!(key instanceof SecretKey)) {
throw new InvalidKeyException("key must be SecretKey");
}
if (hmac == null) {
try {
hmac = Mac.getInstance(getJCAAlgorithm());
} catch (NoSuchAlgorithmException nsae) {
throw new XMLSignatureException(nsae);
}
}
if (outputLengthSet && outputLength < getDigestLength()) {
throw new XMLSignatureException
("HMACOutputLength must not be less than " + getDigestLength());
}
hmac.init(key);
((DOMSignedInfo)si).canonicalize(context, new MacOutputStream(hmac));
return hmac.doFinal();
}
boolean paramsEqual(AlgorithmParameterSpec spec) {
if (getParameterSpec() == spec) {
return true;
}
if (!(spec instanceof HMACParameterSpec)) {
return false;
}
HMACParameterSpec ospec = (HMACParameterSpec)spec;
return outputLength == ospec.getOutputLength();
}
Type getAlgorithmType() {
return Type.HMAC;
}
/**
* Returns the output length of the hash/digest.
*/
abstract int getDigestLength();
static final class SHA1 extends DOMHMACSignatureMethod {
SHA1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return SignatureMethod.HMAC_SHA1;
}
String getJCAAlgorithm() {
return "HmacSHA1";
}
int getDigestLength() {
return 160;
}
}
static final class SHA224 extends DOMHMACSignatureMethod {
SHA224(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA224(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return HMAC_SHA224;
}
@Override
String getJCAAlgorithm() {
return "HmacSHA224";
}
@Override
int getDigestLength() {
return 224;
}
}
static final class SHA256 extends DOMHMACSignatureMethod {
SHA256(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return HMAC_SHA256;
}
String getJCAAlgorithm() {
return "HmacSHA256";
}
int getDigestLength() {
return 256;
}
}
static final class SHA384 extends DOMHMACSignatureMethod {
SHA384(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA384(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return HMAC_SHA384;
}
String getJCAAlgorithm() {
return "HmacSHA384";
}
int getDigestLength() {
return 384;
}
}
static final class SHA512 extends DOMHMACSignatureMethod {
SHA512(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA512(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return HMAC_SHA512;
}
String getJCAAlgorithm() {
return "HmacSHA512";
}
int getDigestLength() {
return 512;
}
}
static final class RIPEMD160 extends DOMHMACSignatureMethod {
RIPEMD160(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
RIPEMD160(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return HMAC_RIPEMD160;
}
@Override
String getJCAAlgorithm() {
return "HMACRIPEMD160";
}
@Override
int getDigestLength() {
return 160;
}
}
}

View File

@@ -0,0 +1,250 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMKeyInfo.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.security.Provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of KeyInfo.
*
*/
public final class DOMKeyInfo extends DOMStructure implements KeyInfo {
private final String id;
private final List<XMLStructure> keyInfoTypes;
/**
* A utility function to suppress casting warnings.
* @param ki
* @return the content of a KeyInfo Object
*/
@SuppressWarnings("unchecked")
public static List<XMLStructure> getContent(KeyInfo ki) {
return ki.getContent();
}
/**
* Creates a {@code DOMKeyInfo}.
*
* @param content a list of one or more {@link XMLStructure}s representing
* key information types. The list is defensively copied to protect
* against subsequent modification.
* @param id an ID attribute
* @throws NullPointerException if {@code content} is {@code null}
* @throws IllegalArgumentException if {@code content} is empty
* @throws ClassCastException if {@code content} contains any entries
* that are not of type {@link XMLStructure}
*/
public DOMKeyInfo(List<? extends XMLStructure> content, String id) {
if (content == null) {
throw new NullPointerException("content cannot be null");
}
this.keyInfoTypes =
Collections.unmodifiableList(new ArrayList<>(content));
if (this.keyInfoTypes.isEmpty()) {
throw new IllegalArgumentException("content cannot be empty");
}
for (int i = 0, size = this.keyInfoTypes.size(); i < size; i++) {
if (!(this.keyInfoTypes.get(i) instanceof XMLStructure)) {
throw new ClassCastException
("content["+i+"] is not a valid KeyInfo type");
}
}
this.id = id;
}
/**
* Creates a {@code DOMKeyInfo} from XML.
*
* @param kiElem KeyInfo element
*/
public DOMKeyInfo(Element kiElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
// get Id attribute, if specified
Attr attr = kiElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
id = attr.getValue();
kiElem.setIdAttributeNode(attr, true);
} else {
id = null;
}
// get all children nodes
List<XMLStructure> content = new ArrayList<>();
Node firstChild = kiElem.getFirstChild();
if (firstChild == null) {
throw new MarshalException("KeyInfo must contain at least one type");
}
while (firstChild != null) {
if (firstChild.getNodeType() == Node.ELEMENT_NODE) {
Element childElem = (Element)firstChild;
String localName = childElem.getLocalName();
String namespace = childElem.getNamespaceURI();
if ("X509Data".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
content.add(new DOMX509Data(childElem));
} else if ("KeyName".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
content.add(new DOMKeyName(childElem));
} else if ("KeyValue".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
content.add(DOMKeyValue.unmarshal(childElem));
} else if ("RetrievalMethod".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
content.add(new DOMRetrievalMethod(childElem,
context, provider));
} else if ("PGPData".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
content.add(new DOMPGPData(childElem));
} else { //may be MgmtData, SPKIData or element from other namespace
content.add(new javax.xml.crypto.dom.DOMStructure(childElem));
}
}
firstChild = firstChild.getNextSibling();
}
keyInfoTypes = Collections.unmodifiableList(content);
}
public String getId() {
return id;
}
public List<XMLStructure> getContent() {
return keyInfoTypes;
}
public void marshal(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
if (parent == null) {
throw new NullPointerException("parent is null");
}
if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("parent must be of type DOMStructure");
}
Node pNode = ((javax.xml.crypto.dom.DOMStructure)parent).getNode();
String dsPrefix = DOMUtils.getSignaturePrefix(context);
Element kiElem = DOMUtils.createElement
(DOMUtils.getOwnerDocument(pNode), "KeyInfo",
XMLSignature.XMLNS, dsPrefix);
if (dsPrefix == null || dsPrefix.length() == 0) {
kiElem.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns", XMLSignature.XMLNS);
} else {
kiElem.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns:" + dsPrefix, XMLSignature.XMLNS);
}
Node nextSibling = null;
if (context instanceof DOMSignContext) {
nextSibling = ((DOMSignContext)context).getNextSibling();
}
marshal(pNode, kiElem, nextSibling, dsPrefix, (DOMCryptoContext)context);
}
@Override
public void marshal(Node parent, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
marshal(parent, null, dsPrefix, context);
}
public void marshal(Node parent, Node nextSibling, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element kiElem = DOMUtils.createElement(ownerDoc, "KeyInfo",
XMLSignature.XMLNS, dsPrefix);
marshal(parent, kiElem, nextSibling, dsPrefix, context);
}
private void marshal(Node parent, Element kiElem, Node nextSibling,
String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
// create and append KeyInfoType elements
for (XMLStructure kiType : keyInfoTypes) {
if (kiType instanceof DOMStructure) {
((DOMStructure)kiType).marshal(kiElem, dsPrefix, context);
} else {
DOMUtils.appendChild(kiElem,
((javax.xml.crypto.dom.DOMStructure)kiType).getNode());
}
}
// append id attribute
DOMUtils.setAttributeID(kiElem, "Id", id);
parent.insertBefore(kiElem, nextSibling);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof KeyInfo)) {
return false;
}
KeyInfo oki = (KeyInfo)o;
boolean idsEqual = id == null ? oki.getId() == null
: id.equals(oki.getId());
return keyInfoTypes.equals(oki.getContent()) && idsEqual;
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
result = 31 * result + keyInfoTypes.hashCode();
return result;
}
}

View File

@@ -0,0 +1,189 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMKeyInfoFactory.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.math.BigInteger;
import java.security.KeyException;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.List;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.KeyName;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.keyinfo.PGPData;
import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of KeyInfoFactory.
*
*/
public final class DOMKeyInfoFactory extends KeyInfoFactory {
public DOMKeyInfoFactory() { }
@SuppressWarnings("rawtypes")
public KeyInfo newKeyInfo(List content) {
return newKeyInfo(content, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public KeyInfo newKeyInfo(List content, String id) {
return new DOMKeyInfo(content, id);
}
public KeyName newKeyName(String name) {
return new DOMKeyName(name);
}
public KeyValue newKeyValue(PublicKey key) throws KeyException {
String algorithm = key.getAlgorithm();
if ("DSA".equals(algorithm)) {
return new DOMKeyValue.DSA((DSAPublicKey) key);
} else if ("RSA".equals(algorithm)) {
return new DOMKeyValue.RSA((RSAPublicKey) key);
} else if ("EC".equals(algorithm)) {
return new DOMKeyValue.EC((ECPublicKey) key);
} else {
throw new KeyException("unsupported key algorithm: " + algorithm);
}
}
public PGPData newPGPData(byte[] keyId) {
return newPGPData(keyId, null, null);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public PGPData newPGPData(byte[] keyId, byte[] keyPacket, List other) {
return new DOMPGPData(keyId, keyPacket, other);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public PGPData newPGPData(byte[] keyPacket, List other) {
return new DOMPGPData(keyPacket, other);
}
public RetrievalMethod newRetrievalMethod(String uri) {
return newRetrievalMethod(uri, null, null);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public RetrievalMethod newRetrievalMethod(String uri, String type,
List transforms) {
if (uri == null) {
throw new NullPointerException("uri must not be null");
}
return new DOMRetrievalMethod(uri, type, transforms);
}
@SuppressWarnings({ "rawtypes" })
public X509Data newX509Data(List content) {
return new DOMX509Data(content);
}
@Override
public X509IssuerSerial newX509IssuerSerial(String issuerName,
BigInteger serialNumber) {
return new DOMX509IssuerSerial(issuerName, serialNumber);
}
public boolean isFeatureSupported(String feature) {
if (feature == null) {
throw new NullPointerException();
} else {
return false;
}
}
public URIDereferencer getURIDereferencer() {
return DOMURIDereferencer.INSTANCE;
}
@Override
public KeyInfo unmarshalKeyInfo(XMLStructure xmlStructure)
throws MarshalException {
if (xmlStructure == null) {
throw new NullPointerException("xmlStructure cannot be null");
}
if (!(xmlStructure instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("xmlStructure must be of type DOMStructure");
}
Node node =
((javax.xml.crypto.dom.DOMStructure) xmlStructure).getNode();
node.normalize();
Element element = null;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
element = ((Document) node).getDocumentElement();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
element = (Element) node;
} else {
throw new MarshalException
("xmlStructure does not contain a proper Node");
}
// check tag
String tag = element.getLocalName();
String namespace = element.getNamespaceURI();
if (tag == null || namespace == null) {
throw new MarshalException("Document implementation must " +
"support DOM Level 2 and be namespace aware");
}
if ("KeyInfo".equals(tag) && XMLSignature.XMLNS.equals(namespace)) {
try {
return new DOMKeyInfo(element, new UnmarshalContext(), getProvider());
} catch (MarshalException me) {
throw me;
} catch (Exception e) {
throw new MarshalException(e);
}
} else {
throw new MarshalException("Invalid KeyInfo tag: " + namespace + ":" + tag);
}
}
private static class UnmarshalContext extends DOMCryptoContext {
UnmarshalContext() {}
}
}

View File

@@ -0,0 +1,105 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMKeyName.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.KeyName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of KeyName.
*
*/
public final class DOMKeyName extends DOMStructure implements KeyName {
private final String name;
/**
* Creates a {@code DOMKeyName}.
*
* @param name the name of the key identifier
* @throws NullPointerException if {@code name} is null
*/
public DOMKeyName(String name) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
}
/**
* Creates a {@code DOMKeyName} from a KeyName element.
*
* @param knElem a KeyName element
*/
public DOMKeyName(Element knElem) {
name = knElem.getFirstChild().getNodeValue();
}
public String getName() {
return name;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
// prepend namespace prefix, if necessary
Element knElem = DOMUtils.createElement(ownerDoc, "KeyName",
XMLSignature.XMLNS, dsPrefix);
knElem.appendChild(ownerDoc.createTextNode(name));
parent.appendChild(knElem);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof KeyName)) {
return false;
}
KeyName okn = (KeyName)obj;
return name.equals(okn.getName());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
return result;
}
}

View File

@@ -0,0 +1,625 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMKeyValue.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.ECField;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of KeyValue.
*
*/
public abstract class DOMKeyValue<K extends PublicKey> extends DOMStructure implements KeyValue {
private static final String XMLDSIG_11_XMLNS
= "http://www.w3.org/2009/xmldsig11#";
private final K publicKey;
public DOMKeyValue(K key) throws KeyException {
if (key == null) {
throw new NullPointerException("key cannot be null");
}
this.publicKey = key;
}
/**
* Creates a {@code DOMKeyValue} from an element.
*
* @param kvtElem a KeyValue child element
*/
public DOMKeyValue(Element kvtElem) throws MarshalException {
this.publicKey = unmarshalKeyValue(kvtElem);
}
static KeyValue unmarshal(Element kvElem) throws MarshalException {
Element kvtElem = DOMUtils.getFirstChildElement(kvElem);
if (kvtElem == null) {
throw new MarshalException("KeyValue must contain at least one type");
}
String namespace = kvtElem.getNamespaceURI();
if (kvtElem.getLocalName().equals("DSAKeyValue") && XMLSignature.XMLNS.equals(namespace)) {
return new DSA(kvtElem);
} else if (kvtElem.getLocalName().equals("RSAKeyValue") && XMLSignature.XMLNS.equals(namespace)) {
return new RSA(kvtElem);
} else if (kvtElem.getLocalName().equals("ECKeyValue") && XMLDSIG_11_XMLNS.equals(namespace)) {
return new EC(kvtElem);
} else {
return new Unknown(kvtElem);
}
}
public PublicKey getPublicKey() throws KeyException {
if (publicKey == null) {
throw new KeyException("can't convert KeyValue to PublicKey");
} else {
return publicKey;
}
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
// create KeyValue element
Element kvElem = DOMUtils.createElement(ownerDoc, "KeyValue",
XMLSignature.XMLNS, dsPrefix);
marshalPublicKey(kvElem, ownerDoc, dsPrefix, context);
parent.appendChild(kvElem);
}
abstract void marshalPublicKey(Node parent, Document doc, String dsPrefix,
DOMCryptoContext context) throws MarshalException;
abstract K unmarshalKeyValue(Element kvtElem)
throws MarshalException;
private static PublicKey generatePublicKey(KeyFactory kf, KeySpec keyspec) {
try {
return kf.generatePublic(keyspec);
} catch (InvalidKeySpecException e) {
//@@@ should dump exception to LOG
return null;
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof KeyValue)) {
return false;
}
try {
KeyValue kv = (KeyValue)obj;
if (publicKey == null ) {
if (kv.getPublicKey() != null) {
return false;
}
} else if (!publicKey.equals(kv.getPublicKey())) {
return false;
}
} catch (KeyException ke) {
// no practical way to determine if the keys are equal
return false;
}
return true;
}
public static BigInteger decode(Element elem) throws MarshalException {
try {
String base64str = elem.getFirstChild().getNodeValue();
return new BigInteger(1, XMLUtils.decode(base64str));
} catch (Exception ex) {
throw new MarshalException(ex);
}
}
@Override
public int hashCode() {
int result = 17;
if (publicKey != null) {
result = 31 * result + publicKey.hashCode();
}
return result;
}
static final class RSA extends DOMKeyValue<RSAPublicKey> {
// RSAKeyValue CryptoBinaries
private DOMCryptoBinary modulus, exponent;
private KeyFactory rsakf;
RSA(RSAPublicKey key) throws KeyException {
super(key);
RSAPublicKey rkey = key;
exponent = new DOMCryptoBinary(rkey.getPublicExponent());
modulus = new DOMCryptoBinary(rkey.getModulus());
}
RSA(Element elem) throws MarshalException {
super(elem);
}
void marshalPublicKey(Node parent, Document doc, String dsPrefix,
DOMCryptoContext context) throws MarshalException {
Element rsaElem = DOMUtils.createElement(doc, "RSAKeyValue",
XMLSignature.XMLNS,
dsPrefix);
Element modulusElem = DOMUtils.createElement(doc, "Modulus",
XMLSignature.XMLNS,
dsPrefix);
Element exponentElem = DOMUtils.createElement(doc, "Exponent",
XMLSignature.XMLNS,
dsPrefix);
modulus.marshal(modulusElem, dsPrefix, context);
exponent.marshal(exponentElem, dsPrefix, context);
rsaElem.appendChild(modulusElem);
rsaElem.appendChild(exponentElem);
parent.appendChild(rsaElem);
}
@Override
RSAPublicKey unmarshalKeyValue(Element kvtElem)
throws MarshalException
{
if (rsakf == null) {
try {
rsakf = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException
("unable to create RSA KeyFactory: " + e.getMessage());
}
}
Element modulusElem = DOMUtils.getFirstChildElement(kvtElem,
"Modulus",
XMLSignature.XMLNS);
BigInteger modulus = decode(modulusElem);
Element exponentElem = DOMUtils.getNextSiblingElement(modulusElem,
"Exponent",
XMLSignature.XMLNS);
BigInteger exponent = decode(exponentElem);
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
return (RSAPublicKey) generatePublicKey(rsakf, spec);
}
}
static final class DSA extends DOMKeyValue<DSAPublicKey> {
// DSAKeyValue CryptoBinaries
private DOMCryptoBinary p, q, g, y; //, seed, pgen;
private KeyFactory dsakf;
DSA(DSAPublicKey key) throws KeyException {
super(key);
DSAPublicKey dkey = key;
DSAParams params = dkey.getParams();
p = new DOMCryptoBinary(params.getP());
q = new DOMCryptoBinary(params.getQ());
g = new DOMCryptoBinary(params.getG());
y = new DOMCryptoBinary(dkey.getY());
}
DSA(Element elem) throws MarshalException {
super(elem);
}
@Override
void marshalPublicKey(Node parent, Document doc, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
Element dsaElem = DOMUtils.createElement(doc, "DSAKeyValue",
XMLSignature.XMLNS,
dsPrefix);
// parameters J, Seed & PgenCounter are not included
Element pElem = DOMUtils.createElement(doc, "P", XMLSignature.XMLNS,
dsPrefix);
Element qElem = DOMUtils.createElement(doc, "Q", XMLSignature.XMLNS,
dsPrefix);
Element gElem = DOMUtils.createElement(doc, "G", XMLSignature.XMLNS,
dsPrefix);
Element yElem = DOMUtils.createElement(doc, "Y", XMLSignature.XMLNS,
dsPrefix);
p.marshal(pElem, dsPrefix, context);
q.marshal(qElem, dsPrefix, context);
g.marshal(gElem, dsPrefix, context);
y.marshal(yElem, dsPrefix, context);
dsaElem.appendChild(pElem);
dsaElem.appendChild(qElem);
dsaElem.appendChild(gElem);
dsaElem.appendChild(yElem);
parent.appendChild(dsaElem);
}
@Override
DSAPublicKey unmarshalKeyValue(Element kvtElem)
throws MarshalException
{
if (dsakf == null) {
try {
dsakf = KeyFactory.getInstance("DSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException
("unable to create DSA KeyFactory: " + e.getMessage());
}
}
Element curElem = DOMUtils.getFirstChildElement(kvtElem);
if (curElem == null) {
throw new MarshalException("KeyValue must contain at least one type");
}
// check for P and Q
BigInteger p = null;
BigInteger q = null;
if (curElem.getLocalName().equals("P") && XMLSignature.XMLNS.equals(curElem.getNamespaceURI())) {
p = decode(curElem);
curElem = DOMUtils.getNextSiblingElement(curElem, "Q", XMLSignature.XMLNS);
q = decode(curElem);
curElem = DOMUtils.getNextSiblingElement(curElem);
}
BigInteger g = null;
if (curElem != null
&& curElem.getLocalName().equals("G") && XMLSignature.XMLNS.equals(curElem.getNamespaceURI())) {
g = decode(curElem);
curElem = DOMUtils.getNextSiblingElement(curElem, "Y", XMLSignature.XMLNS);
}
BigInteger y = null;
if (curElem != null) {
y = decode(curElem);
curElem = DOMUtils.getNextSiblingElement(curElem);
}
//if (curElem != null && curElem.getLocalName().equals("J")) {
//j = new DOMCryptoBinary(curElem.getFirstChild());
// curElem = DOMUtils.getNextSiblingElement(curElem);
//}
//@@@ do we care about j, pgenCounter or seed?
DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g);
return (DSAPublicKey) generatePublicKey(dsakf, spec);
}
}
static final class EC extends DOMKeyValue<ECPublicKey> {
// ECKeyValue CryptoBinaries
private byte[] ecPublicKey;
private KeyFactory eckf;
private ECParameterSpec ecParams;
/* Supported curve, secp256r1 */
private static final Curve SECP256R1 = initializeCurve(
"secp256r1 [NIST P-256, X9.62 prime256v1]",
"1.2.840.10045.3.1.7",
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1
);
/* Supported curve secp384r1 */
private static final Curve SECP384R1 = initializeCurve(
"secp384r1 [NIST P-384]",
"1.3.132.0.34",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
1
);
/* Supported curve secp521r1 */
private static final Curve SECP521R1 = initializeCurve(
"secp521r1 [NIST P-521]",
"1.3.132.0.35",
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
1
);
private static Curve initializeCurve(String name, String oid,
String sfield, String a, String b,
String x, String y, String n, int h) {
BigInteger p = bigInt(sfield);
ECField field = new ECFieldFp(p);
EllipticCurve curve = new EllipticCurve(field, bigInt(a),
bigInt(b));
ECPoint g = new ECPoint(bigInt(x), bigInt(y));
return new Curve(name, oid, curve, g, bigInt(n), h);
}
EC(ECPublicKey ecKey) throws KeyException {
super(ecKey);
ECPoint ecPoint = ecKey.getW();
ecParams = ecKey.getParams();
ecPublicKey = encodePoint(ecPoint, ecParams.getCurve());
}
EC(Element dmElem) throws MarshalException {
super(dmElem);
}
private static ECPoint decodePoint(byte[] data, EllipticCurve curve)
throws IOException {
if (data.length == 0 || data[0] != 4) {
throw new IOException("Only uncompressed point format " +
"supported");
}
// Per ANSI X9.62, an encoded point is a 1 byte type followed by
// ceiling(LOG base 2 field-size / 8) bytes of x and the same of y.
int n = (data.length - 1) / 2;
if (n != (curve.getField().getFieldSize() + 7) >> 3) {
throw new IOException("Point does not match field size");
}
byte[] xb = Arrays.copyOfRange(data, 1, 1 + n);
byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n);
return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb));
}
private static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
// get field size in bytes (rounding up)
int n = (curve.getField().getFieldSize() + 7) >> 3;
byte[] xb = trimZeroes(point.getAffineX().toByteArray());
byte[] yb = trimZeroes(point.getAffineY().toByteArray());
if (xb.length > n || yb.length > n) {
throw new RuntimeException("Point coordinates do not " +
"match field size");
}
byte[] b = new byte[1 + (n << 1)];
b[0] = 4; // uncompressed
System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length);
System.arraycopy(yb, 0, b, b.length - yb.length, yb.length);
return b;
}
private static byte[] trimZeroes(byte[] b) {
int i = 0;
while (i < b.length - 1 && b[i] == 0) {
i++;
}
if (i == 0) {
return b;
}
return Arrays.copyOfRange(b, i, b.length);
}
private static String getCurveOid(ECParameterSpec params) {
// Check that the params represent one of the supported
// curves. If there is a match, return the object identifier
// of the curve.
Curve match;
if (matchCurve(params, SECP256R1)) {
match = SECP256R1;
} else if (matchCurve(params, SECP384R1)) {
match = SECP384R1;
} else if (matchCurve(params, SECP521R1)) {
match = SECP521R1;
} else {
return null;
}
return match.getObjectId();
}
private static boolean matchCurve(ECParameterSpec params, Curve curve) {
int fieldSize = params.getCurve().getField().getFieldSize();
if (curve.getCurve().getField().getFieldSize() == fieldSize
&& curve.getCurve().equals(params.getCurve())
&& curve.getGenerator().equals(params.getGenerator())
&& curve.getOrder().equals(params.getOrder())
&& curve.getCofactor() == params.getCofactor()) {
return true;
} else {
return false;
}
}
@Override
void marshalPublicKey(Node parent, Document doc, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
String prefix = DOMUtils.getNSPrefix(context, XMLDSIG_11_XMLNS);
Element ecKeyValueElem = DOMUtils.createElement(doc, "ECKeyValue",
XMLDSIG_11_XMLNS,
prefix);
Element namedCurveElem = DOMUtils.createElement(doc, "NamedCurve",
XMLDSIG_11_XMLNS,
prefix);
Element publicKeyElem = DOMUtils.createElement(doc, "PublicKey",
XMLDSIG_11_XMLNS,
prefix);
String oid = getCurveOid(ecParams);
if (oid == null) {
throw new MarshalException("Invalid ECParameterSpec");
}
DOMUtils.setAttribute(namedCurveElem, "URI", "urn:oid:" + oid);
String qname = prefix == null || prefix.length() == 0
? "xmlns" : "xmlns:" + prefix;
namedCurveElem.setAttributeNS("http://www.w3.org/2000/xmlns/",
qname, XMLDSIG_11_XMLNS);
ecKeyValueElem.appendChild(namedCurveElem);
String encoded = XMLUtils.encodeToString(ecPublicKey);
publicKeyElem.appendChild
(DOMUtils.getOwnerDocument(publicKeyElem).createTextNode(encoded));
ecKeyValueElem.appendChild(publicKeyElem);
parent.appendChild(ecKeyValueElem);
}
@Override
ECPublicKey unmarshalKeyValue(Element kvtElem)
throws MarshalException
{
if (eckf == null) {
try {
eckf = KeyFactory.getInstance("EC");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException
("unable to create EC KeyFactory: " + e.getMessage());
}
}
ECParameterSpec ecParams = null;
Element curElem = DOMUtils.getFirstChildElement(kvtElem);
if (curElem == null) {
throw new MarshalException("KeyValue must contain at least one type");
}
if (curElem.getLocalName().equals("ECParameters")
&& XMLDSIG_11_XMLNS.equals(curElem.getNamespaceURI())) {
throw new UnsupportedOperationException
("ECParameters not supported");
} else if (curElem.getLocalName().equals("NamedCurve")
&& XMLDSIG_11_XMLNS.equals(curElem.getNamespaceURI())) {
String uri = DOMUtils.getAttributeValue(curElem, "URI");
// strip off "urn:oid"
if (uri.startsWith("urn:oid:")) {
String oid = uri.substring("urn:oid:".length());
ecParams = getECParameterSpec(oid);
if (ecParams == null) {
throw new MarshalException("Invalid curve OID");
}
} else {
throw new MarshalException("Invalid NamedCurve URI");
}
} else {
throw new MarshalException("Invalid ECKeyValue");
}
curElem = DOMUtils.getNextSiblingElement(curElem, "PublicKey", XMLDSIG_11_XMLNS);
ECPoint ecPoint = null;
try {
String content = XMLUtils.getFullTextChildrenFromNode(curElem);
ecPoint = decodePoint(XMLUtils.decode(content),
ecParams.getCurve());
} catch (IOException ioe) {
throw new MarshalException("Invalid EC Point", ioe);
}
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParams);
return (ECPublicKey) generatePublicKey(eckf, spec);
}
private static ECParameterSpec getECParameterSpec(String oid) {
if (oid.equals(SECP256R1.getObjectId())) {
return SECP256R1;
} else if (oid.equals(SECP384R1.getObjectId())) {
return SECP384R1;
} else if (oid.equals(SECP521R1.getObjectId())) {
return SECP521R1;
} else {
return null;
}
}
static final class Curve extends ECParameterSpec {
private final String name;
private final String oid;
Curve(String name, String oid, EllipticCurve curve,
ECPoint g, BigInteger n, int h) {
super(curve, g, n, h);
this.name = name;
this.oid = oid;
}
private String getName() {
return name;
}
private String getObjectId() {
return oid;
}
}
}
private static BigInteger bigInt(String s) {
return new BigInteger(s, 16);
}
static final class Unknown extends DOMKeyValue<PublicKey> {
private javax.xml.crypto.dom.DOMStructure externalPublicKey;
Unknown(Element elem) throws MarshalException {
super(elem);
}
@Override
PublicKey unmarshalKeyValue(Element kvElem) throws MarshalException {
externalPublicKey = new javax.xml.crypto.dom.DOMStructure(kvElem);
return null;
}
@Override
void marshalPublicKey(Node parent, Document doc, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
parent.appendChild(externalPublicKey.getNode());
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMManifest.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import java.security.Provider;
import java.util.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of Manifest.
*
*/
public final class DOMManifest extends DOMStructure implements Manifest {
private final List<Reference> references;
private final String id;
/**
* Creates a {@code DOMManifest} containing the specified
* list of {@link Reference}s and optional id.
*
* @param references a list of one or more {@code Reference}s. The list
* is defensively copied to protect against subsequent modification.
* @param id the id (may be {@code null}
* @throws NullPointerException if {@code references} is
* {@code null}
* @throws IllegalArgumentException if {@code references} is empty
* @throws ClassCastException if {@code references} contains any
* entries that are not of type {@link Reference}
*/
public DOMManifest(List<? extends Reference> references, String id) {
if (references == null) {
throw new NullPointerException("references cannot be null");
}
this.references =
Collections.unmodifiableList(new ArrayList<>(references));
if (this.references.isEmpty()) {
throw new IllegalArgumentException("list of references must " +
"contain at least one entry");
}
for (int i = 0, size = this.references.size(); i < size; i++) {
if (!(this.references.get(i) instanceof Reference)) {
throw new ClassCastException
("references["+i+"] is not a valid type");
}
}
this.id = id;
}
/**
* Creates a {@code DOMManifest} from an element.
*
* @param manElem a Manifest element
*/
public DOMManifest(Element manElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
this.id = DOMUtils.getIdAttributeValue(manElem, "Id");
boolean secVal = Utils.secureValidation(context);
Element refElem = DOMUtils.getFirstChildElement(manElem, "Reference", XMLSignature.XMLNS);
List<Reference> refs = new ArrayList<>();
refs.add(new DOMReference(refElem, context, provider));
refElem = DOMUtils.getNextSiblingElement(refElem);
while (refElem != null) {
String localName = refElem.getLocalName();
String namespace = refElem.getNamespaceURI();
if (!"Reference".equals(localName) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " +
namespace + ":" + localName + ", expected Reference");
}
refs.add(new DOMReference(refElem, context, provider));
if (secVal && Policy.restrictNumReferences(refs.size())) {
String error = "A maxiumum of " + Policy.maxReferences()
+ " references per Manifest are allowed when"
+ " secure validation is enabled";
throw new MarshalException(error);
}
refElem = DOMUtils.getNextSiblingElement(refElem);
}
this.references = Collections.unmodifiableList(refs);
}
public String getId() {
return id;
}
@SuppressWarnings("unchecked")
public static List<Reference> getManifestReferences(Manifest mf) {
return mf.getReferences();
}
@Override
public List<Reference> getReferences() {
return references;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element manElem = DOMUtils.createElement(ownerDoc, "Manifest",
XMLSignature.XMLNS, dsPrefix);
DOMUtils.setAttributeID(manElem, "Id", id);
// add references
for (Reference ref : references) {
((DOMReference)ref).marshal(manElem, dsPrefix, context);
}
parent.appendChild(manElem);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Manifest)) {
return false;
}
Manifest oman = (Manifest)o;
boolean idsEqual = id == null ? oman.getId() == null
: id.equals(oman.getId());
return idsEqual && references.equals(oman.getReferences());
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
result = 31 * result + references.hashCode();
return result;
}
}

View File

@@ -0,0 +1,261 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMPGPData.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.util.*;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.PGPData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
/**
* DOM-based implementation of PGPData.
*
*/
public final class DOMPGPData extends DOMStructure implements PGPData {
private final byte[] keyId;
private final byte[] keyPacket;
private final List<XMLStructure> externalElements;
/**
* Creates a {@code DOMPGPData} containing the specified key packet.
* and optional list of external elements.
*
* @param keyPacket a PGP Key Material Packet as defined in section 5.5 of
* <a href="https://www.ietf.org/rfc/rfc2440.txt">RFC 2440</a>. The
* array is cloned to prevent subsequent modification.
* @param other a list of {@link XMLStructure}s representing elements from
* an external namespace. The list is defensively copied to prevent
* subsequent modification. May be {@code null} or empty.
* @throws NullPointerException if {@code keyPacket} is
* {@code null}
* @throws IllegalArgumentException if the key packet is not in the
* correct format
* @throws ClassCastException if {@code other} contains any
* entries that are not of type {@link XMLStructure}
*/
public DOMPGPData(byte[] keyPacket, List<? extends XMLStructure> other) {
if (keyPacket == null) {
throw new NullPointerException("keyPacket cannot be null");
}
if (other == null || other.isEmpty()) {
this.externalElements = Collections.emptyList();
} else {
this.externalElements =
Collections.unmodifiableList(new ArrayList<>(other));
for (int i = 0, size = this.externalElements.size(); i < size; i++) {
if (!(this.externalElements.get(i) instanceof XMLStructure)) {
throw new ClassCastException
("other["+i+"] is not a valid PGPData type");
}
}
}
this.keyPacket = (byte[])keyPacket.clone();
checkKeyPacket(keyPacket);
this.keyId = null;
}
/**
* Creates a {@code DOMPGPData} containing the specified key id and
* optional key packet and list of external elements.
*
* @param keyId a PGP public key id as defined in section 11.2 of
* <a href="https://www.ietf.org/rfc/rfc2440.txt">RFC 2440</a>. The
* array is cloned to prevent subsequent modification.
* @param keyPacket a PGP Key Material Packet as defined in section 5.5 of
* <a href="https://www.ietf.org/rfc/rfc2440.txt">RFC 2440</a> (may
* be {@code null}). The array is cloned to prevent subsequent
* modification.
* @param other a list of {@link XMLStructure}s representing elements from
* an external namespace. The list is defensively copied to prevent
* subsequent modification. May be {@code null} or empty.
* @throws NullPointerException if {@code keyId} is {@code null}
* @throws IllegalArgumentException if the key id or packet is not in the
* correct format
* @throws ClassCastException if {@code other} contains any
* entries that are not of type {@link XMLStructure}
*/
public DOMPGPData(byte[] keyId, byte[] keyPacket,
List<? extends XMLStructure> other)
{
if (keyId == null) {
throw new NullPointerException("keyId cannot be null");
}
// key ids must be 8 bytes
if (keyId.length != 8) {
throw new IllegalArgumentException("keyId must be 8 bytes long");
}
if (other == null || other.isEmpty()) {
this.externalElements = Collections.emptyList();
} else {
this.externalElements =
Collections.unmodifiableList(new ArrayList<>(other));
for (int i = 0, size = this.externalElements.size(); i < size; i++) {
if (!(this.externalElements.get(i) instanceof XMLStructure)) {
throw new ClassCastException
("other["+i+"] is not a valid PGPData type");
}
}
}
this.keyId = (byte[])keyId.clone();
this.keyPacket = keyPacket == null ? null
: (byte[])keyPacket.clone();
if (keyPacket != null) {
checkKeyPacket(keyPacket);
}
}
/**
* Creates a {@code DOMPGPData} from an element.
*
* @param pdElem a PGPData element
*/
public DOMPGPData(Element pdElem) throws MarshalException {
// get all children nodes
byte[] pgpKeyId = null;
byte[] pgpKeyPacket = null;
List<XMLStructure> other = new ArrayList<>();
Node firstChild = pdElem.getFirstChild();
while (firstChild != null) {
if (firstChild.getNodeType() == Node.ELEMENT_NODE) {
Element childElem = (Element)firstChild;
String localName = childElem.getLocalName();
String namespace = childElem.getNamespaceURI();
if ("PGPKeyID".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
String content = XMLUtils.getFullTextChildrenFromNode(childElem);
pgpKeyId = XMLUtils.decode(content);
} else if ("PGPKeyPacket".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
String content = XMLUtils.getFullTextChildrenFromNode(childElem);
pgpKeyPacket = XMLUtils.decode(content);
} else {
other.add
(new javax.xml.crypto.dom.DOMStructure(childElem));
}
}
firstChild = firstChild.getNextSibling();
}
this.keyId = pgpKeyId;
this.keyPacket = pgpKeyPacket;
this.externalElements = Collections.unmodifiableList(other);
}
public byte[] getKeyId() {
return keyId == null ? null : keyId.clone();
}
public byte[] getKeyPacket() {
return keyPacket == null ? null : keyPacket.clone();
}
public List<XMLStructure> getExternalElements() {
return externalElements;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element pdElem = DOMUtils.createElement(ownerDoc, "PGPData",
XMLSignature.XMLNS, dsPrefix);
// create and append PGPKeyID element
if (keyId != null) {
Element keyIdElem = DOMUtils.createElement(ownerDoc, "PGPKeyID",
XMLSignature.XMLNS,
dsPrefix);
keyIdElem.appendChild
(ownerDoc.createTextNode(XMLUtils.encodeToString(keyId)));
pdElem.appendChild(keyIdElem);
}
// create and append PGPKeyPacket element
if (keyPacket != null) {
Element keyPktElem = DOMUtils.createElement(ownerDoc,
"PGPKeyPacket",
XMLSignature.XMLNS,
dsPrefix);
keyPktElem.appendChild
(ownerDoc.createTextNode(XMLUtils.encodeToString(keyPacket)));
pdElem.appendChild(keyPktElem);
}
// create and append any elements
for (XMLStructure extElem : externalElements) {
DOMUtils.appendChild(pdElem, ((javax.xml.crypto.dom.DOMStructure)
extElem).getNode());
}
parent.appendChild(pdElem);
}
/**
* We assume packets use the new format packet syntax, as specified in
* section 4 of RFC 2440.
*
* This method only checks if the packet contains a valid tag. The
* contents of the packet should be checked by the application.
*/
private void checkKeyPacket(byte[] keyPacket) {
// length must be at least 3 (one byte for tag, one byte for length,
// and minimally one byte of content
if (keyPacket.length < 3) {
throw new IllegalArgumentException("keypacket must be at least " +
"3 bytes long");
}
int tag = keyPacket[0];
// first bit must be set
if ((tag & 128) != 128) {
throw new IllegalArgumentException("keypacket tag is invalid: " +
"bit 7 is not set");
}
// make sure using new format
if ((tag & 64) != 64) {
throw new IllegalArgumentException("old keypacket tag format is " +
"unsupported");
}
// tag value must be 6, 14, 5 or 7
if ((tag & 6) != 6 && (tag & 14) != 14 &&
(tag & 5) != 5 && (tag & 7) != 7) {
throw new IllegalArgumentException("keypacket tag is invalid: " +
"must be 6, 14, 5, or 7");
}
}
}

View File

@@ -0,0 +1,656 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Portions copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* ===========================================================================
*
* (C) Copyright IBM Corp. 2003 All Rights Reserved.
*
* ===========================================================================
*/
/*
* $Id: DOMReference.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dom.DOMURIReference;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.*;
import java.util.*;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.jcp.xml.dsig.internal.DigesterOutputStream;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream;
/**
* DOM-based implementation of Reference.
*
*/
public final class DOMReference extends DOMStructure
implements Reference, DOMURIReference {
/**
* The maximum number of transforms per reference, if secure validation is enabled.
*/
public static final int MAXIMUM_TRANSFORM_COUNT = 5;
/**
* Look up useC14N11 system property. If true, an explicit C14N11 transform
* will be added if necessary when generating the signature. See section
* 3.1.1 of http://www.w3.org/2007/xmlsec/Drafts/xmldsig-core/ for more info.
*
* If true, overrides the same property if set in the XMLSignContext.
*/
private static boolean useC14N11 =
AccessController.doPrivileged((PrivilegedAction<Boolean>)
() -> Boolean.getBoolean("com.sun.org.apache.xml.internal.security.useC14N11"));
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMReference.class);
private final DigestMethod digestMethod;
private final String id;
private final List<Transform> transforms;
private List<Transform> allTransforms;
private final Data appliedTransformData;
private Attr here;
private final String uri;
private final String type;
private byte[] digestValue;
private byte[] calcDigestValue;
private Element refElem;
private boolean digested = false;
private boolean validated = false;
private boolean validationStatus;
private Data derefData;
private InputStream dis;
private MessageDigest md;
private Provider provider;
/**
* Creates a {@code Reference} from the specified parameters.
*
* @param uri the URI (may be null)
* @param type the type (may be null)
* @param dm the digest method
* @param transforms a list of {@link Transform}s. The list
* is defensively copied to protect against subsequent modification.
* May be {@code null} or empty.
* @param id the reference ID (may be {@code null})
* @throws NullPointerException if {@code dm} is {@code null}
* @throws ClassCastException if any of the {@code transforms} are
* not of type {@code Transform}
*/
public DOMReference(String uri, String type, DigestMethod dm,
List<? extends Transform> transforms, String id,
Provider provider)
{
this(uri, type, dm, null, null, transforms, id, null, provider);
}
public DOMReference(String uri, String type, DigestMethod dm,
List<? extends Transform> appliedTransforms,
Data result, List<? extends Transform> transforms,
String id, Provider provider)
{
this(uri, type, dm, appliedTransforms,
result, transforms, id, null, provider);
}
public DOMReference(String uri, String type, DigestMethod dm,
List<? extends Transform> appliedTransforms,
Data result, List<? extends Transform> transforms,
String id, byte[] digestValue, Provider provider)
{
if (dm == null) {
throw new NullPointerException("DigestMethod must be non-null");
}
if (appliedTransforms == null) {
this.allTransforms = new ArrayList<>();
} else {
this.allTransforms = new ArrayList<>(appliedTransforms);
for (int i = 0, size = this.allTransforms.size(); i < size; i++) {
if (!(this.allTransforms.get(i) instanceof Transform)) {
throw new ClassCastException
("appliedTransforms["+i+"] is not a valid type");
}
}
}
if (transforms == null) {
this.transforms = Collections.emptyList();
} else {
this.transforms = new ArrayList<>(transforms);
for (int i = 0, size = this.transforms.size(); i < size; i++) {
if (!(this.transforms.get(i) instanceof Transform)) {
throw new ClassCastException
("transforms["+i+"] is not a valid type");
}
}
this.allTransforms.addAll(this.transforms);
}
this.digestMethod = dm;
this.uri = uri;
if (uri != null && !uri.equals("")) {
try {
new URI(uri);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
this.type = type;
this.id = id;
if (digestValue != null) {
this.digestValue = (byte[])digestValue.clone();
this.digested = true;
}
this.appliedTransformData = result;
this.provider = provider;
}
/**
* Creates a {@code DOMReference} from an element.
*
* @param refElem a Reference element
*/
public DOMReference(Element refElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
boolean secVal = Utils.secureValidation(context);
// unmarshal Transforms, if specified
Element nextSibling = DOMUtils.getFirstChildElement(refElem);
List<Transform> newTransforms = new ArrayList<>(MAXIMUM_TRANSFORM_COUNT);
if (nextSibling.getLocalName().equals("Transforms")
&& XMLSignature.XMLNS.equals(nextSibling.getNamespaceURI())) {
Element transformElem = DOMUtils.getFirstChildElement(nextSibling,
"Transform",
XMLSignature.XMLNS);
newTransforms.add(new DOMTransform(transformElem, context, provider));
transformElem = DOMUtils.getNextSiblingElement(transformElem);
while (transformElem != null) {
String localName = transformElem.getLocalName();
String namespace = transformElem.getNamespaceURI();
if (!"Transform".equals(localName) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException(
"Invalid element name: " + localName +
", expected Transform");
}
newTransforms.add
(new DOMTransform(transformElem, context, provider));
if (secVal && Policy.restrictNumTransforms(newTransforms.size())) {
String error = "A maximum of " + Policy.maxTransforms()
+ " transforms per Reference are allowed when"
+ " secure validation is enabled";
throw new MarshalException(error);
}
transformElem = DOMUtils.getNextSiblingElement(transformElem);
}
nextSibling = DOMUtils.getNextSiblingElement(nextSibling);
}
if (!nextSibling.getLocalName().equals("DigestMethod")
&& XMLSignature.XMLNS.equals(nextSibling.getNamespaceURI())) {
throw new MarshalException("Invalid element name: " +
nextSibling.getLocalName() +
", expected DigestMethod");
}
// unmarshal DigestMethod
Element dmElem = nextSibling;
this.digestMethod = DOMDigestMethod.unmarshal(dmElem);
String digestMethodAlgorithm = this.digestMethod.getAlgorithm();
if (secVal && Policy.restrictAlg(digestMethodAlgorithm)) {
throw new MarshalException(
"It is forbidden to use algorithm " + digestMethodAlgorithm +
" when secure validation is enabled"
);
}
// unmarshal DigestValue
Element dvElem = DOMUtils.getNextSiblingElement(dmElem, "DigestValue", XMLSignature.XMLNS);
String content = XMLUtils.getFullTextChildrenFromNode(dvElem);
this.digestValue = XMLUtils.decode(content);
// check for extra elements
if (DOMUtils.getNextSiblingElement(dvElem) != null) {
throw new MarshalException(
"Unexpected element after DigestValue element");
}
// unmarshal attributes
this.uri = DOMUtils.getAttributeValue(refElem, "URI");
Attr attr = refElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
this.id = attr.getValue();
refElem.setIdAttributeNode(attr, true);
} else {
this.id = null;
}
this.type = DOMUtils.getAttributeValue(refElem, "Type");
this.here = refElem.getAttributeNodeNS(null, "URI");
this.refElem = refElem;
this.transforms = newTransforms;
this.allTransforms = transforms;
this.appliedTransformData = null;
this.provider = provider;
}
public DigestMethod getDigestMethod() {
return digestMethod;
}
public String getId() {
return id;
}
public String getURI() {
return uri;
}
public String getType() {
return type;
}
public List<Transform> getTransforms() {
return Collections.unmodifiableList(allTransforms);
}
public byte[] getDigestValue() {
return digestValue == null ? null : digestValue.clone();
}
public byte[] getCalculatedDigestValue() {
return calcDigestValue == null ? null
: calcDigestValue.clone();
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
LOG.debug("Marshalling Reference");
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
refElem = DOMUtils.createElement(ownerDoc, "Reference",
XMLSignature.XMLNS, dsPrefix);
// set attributes
DOMUtils.setAttributeID(refElem, "Id", id);
DOMUtils.setAttribute(refElem, "URI", uri);
DOMUtils.setAttribute(refElem, "Type", type);
// create and append Transforms element
if (!allTransforms.isEmpty()) {
Element transformsElem = DOMUtils.createElement(ownerDoc,
"Transforms",
XMLSignature.XMLNS,
dsPrefix);
refElem.appendChild(transformsElem);
for (Transform transform : allTransforms) {
((DOMStructure)transform).marshal(transformsElem,
dsPrefix, context);
}
}
// create and append DigestMethod element
((DOMDigestMethod)digestMethod).marshal(refElem, dsPrefix, context);
// create and append DigestValue element
LOG.debug("Adding digestValueElem");
Element digestValueElem = DOMUtils.createElement(ownerDoc,
"DigestValue",
XMLSignature.XMLNS,
dsPrefix);
if (digestValue != null) {
digestValueElem.appendChild
(ownerDoc.createTextNode(XMLUtils.encodeToString(digestValue)));
}
refElem.appendChild(digestValueElem);
parent.appendChild(refElem);
here = refElem.getAttributeNodeNS(null, "URI");
}
public void digest(XMLSignContext signContext)
throws XMLSignatureException
{
Data data = null;
if (appliedTransformData == null) {
data = dereference(signContext);
} else {
data = appliedTransformData;
}
digestValue = transform(data, signContext);
// insert digestValue into DigestValue element
String encodedDV = XMLUtils.encodeToString(digestValue);
LOG.debug("Reference object uri = {}", uri);
Element digestElem = DOMUtils.getLastChildElement(refElem);
if (digestElem == null) {
throw new XMLSignatureException("DigestValue element expected");
}
DOMUtils.removeAllChildren(digestElem);
digestElem.appendChild
(refElem.getOwnerDocument().createTextNode(encodedDV));
digested = true;
LOG.debug("Reference digesting completed");
}
public boolean validate(XMLValidateContext validateContext)
throws XMLSignatureException
{
if (validateContext == null) {
throw new NullPointerException("validateContext cannot be null");
}
if (validated) {
return validationStatus;
}
Data data = dereference(validateContext);
calcDigestValue = transform(data, validateContext);
if (LOG.isDebugEnabled()) {
LOG.debug("Expected digest: " + XMLUtils.encodeToString(digestValue));
LOG.debug("Actual digest: " + XMLUtils.encodeToString(calcDigestValue));
}
validationStatus = Arrays.equals(digestValue, calcDigestValue);
validated = true;
return validationStatus;
}
public Data getDereferencedData() {
return derefData;
}
public InputStream getDigestInputStream() {
return dis;
}
private Data dereference(XMLCryptoContext context)
throws XMLSignatureException
{
Data data = null;
// use user-specified URIDereferencer if specified; otherwise use deflt
URIDereferencer deref = context.getURIDereferencer();
if (deref == null) {
deref = DOMURIDereferencer.INSTANCE;
}
try {
data = deref.dereference(this, context);
LOG.debug("URIDereferencer class name: {}", deref.getClass().getName());
LOG.debug("Data class name: {}", data.getClass().getName());
} catch (URIReferenceException ure) {
throw new XMLSignatureException(ure);
}
return data;
}
private byte[] transform(Data dereferencedData,
XMLCryptoContext context)
throws XMLSignatureException
{
if (md == null) {
try {
md = MessageDigest.getInstance
(((DOMDigestMethod)digestMethod).getMessageDigestAlgorithm());
} catch (NoSuchAlgorithmException nsae) {
throw new XMLSignatureException(nsae);
}
}
md.reset();
DigesterOutputStream dos;
Boolean cache = (Boolean)
context.getProperty("javax.xml.crypto.dsig.cacheReference");
if (cache != null && cache) {
this.derefData = copyDerefData(dereferencedData);
dos = new DigesterOutputStream(md, true);
} else {
dos = new DigesterOutputStream(md);
}
Data data = dereferencedData;
try (OutputStream os = new UnsyncBufferedOutputStream(dos)) {
for (int i = 0, size = transforms.size(); i < size; i++) {
DOMTransform transform = (DOMTransform)transforms.get(i);
if (i < size - 1) {
data = transform.transform(data, context);
} else {
data = transform.transform(data, context, os);
}
}
if (data != null) {
XMLSignatureInput xi;
// explicitly use C14N 1.1 when generating signature
// first check system property, then context property
boolean c14n11 = useC14N11;
String c14nalg = CanonicalizationMethod.INCLUSIVE;
if (context instanceof XMLSignContext) {
if (!c14n11) {
Boolean prop = (Boolean)context.getProperty
("com.sun.org.apache.xml.internal.security.useC14N11");
c14n11 = prop != null && prop;
if (c14n11) {
c14nalg = "http://www.w3.org/2006/12/xml-c14n11";
}
} else {
c14nalg = "http://www.w3.org/2006/12/xml-c14n11";
}
}
if (data instanceof ApacheData) {
xi = ((ApacheData)data).getXMLSignatureInput();
} else if (data instanceof OctetStreamData) {
xi = new XMLSignatureInput
(((OctetStreamData)data).getOctetStream());
} else if (data instanceof NodeSetData) {
TransformService spi = null;
if (provider == null) {
spi = TransformService.getInstance(c14nalg, "DOM");
} else {
try {
spi = TransformService.getInstance(c14nalg, "DOM", provider);
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(c14nalg, "DOM");
}
}
data = spi.transform(data, context);
xi = new XMLSignatureInput
(((OctetStreamData)data).getOctetStream());
} else {
throw new XMLSignatureException("unrecognized Data type");
}
boolean secVal = Utils.secureValidation(context);
try {
xi.setSecureValidation(secVal);
if (context instanceof XMLSignContext && c14n11
&& !xi.isOctetStream() && !xi.isOutputStreamSet()) {
TransformService spi = null;
if (provider == null) {
spi = TransformService.getInstance(c14nalg, "DOM");
} else {
try {
spi = TransformService.getInstance(c14nalg, "DOM", provider);
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(c14nalg, "DOM");
}
}
DOMTransform t = new DOMTransform(spi);
Element transformsElem = null;
String dsPrefix = DOMUtils.getSignaturePrefix(context);
if (allTransforms.isEmpty()) {
transformsElem = DOMUtils.createElement(
refElem.getOwnerDocument(),
"Transforms", XMLSignature.XMLNS, dsPrefix);
refElem.insertBefore(transformsElem,
DOMUtils.getFirstChildElement(refElem));
} else {
transformsElem = DOMUtils.getFirstChildElement(refElem);
}
t.marshal(transformsElem, dsPrefix,
(DOMCryptoContext) context);
allTransforms.add(t);
xi.updateOutputStream(os, true);
} else {
xi.updateOutputStream(os);
}
} finally {
if(xi.getOctetStreamReal() != null) {
xi.getOctetStreamReal().close();
}
}
}
os.flush();
if (cache != null && cache) {
this.dis = dos.getInputStream();
}
return dos.getDigestValue();
} catch (NoSuchAlgorithmException e) {
throw new XMLSignatureException(e);
} catch (TransformException e) {
throw new XMLSignatureException(e);
} catch (MarshalException e) {
throw new XMLSignatureException(e);
} catch (IOException e) {
throw new XMLSignatureException(e);
} catch (com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException e) {
throw new XMLSignatureException(e);
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
throw new XMLSignatureException(e);
}
}
}
}
public Node getHere() {
return here;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Reference)) {
return false;
}
Reference oref = (Reference)o;
boolean idsEqual = id == null ? oref.getId() == null
: id.equals(oref.getId());
boolean urisEqual = uri == null ? oref.getURI() == null
: uri.equals(oref.getURI());
boolean typesEqual = type == null ? oref.getType() == null
: type.equals(oref.getType());
boolean digestValuesEqual =
Arrays.equals(digestValue, oref.getDigestValue());
return digestMethod.equals(oref.getDigestMethod()) && idsEqual &&
urisEqual && typesEqual &&
allTransforms.equals(oref.getTransforms()) && digestValuesEqual;
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
if (uri != null) {
result = 31 * result + uri.hashCode();
}
if (type != null) {
result = 31 * result + type.hashCode();
}
if (digestValue != null) {
result = 31 * result + Arrays.hashCode(digestValue);
}
result = 31 * result + digestMethod.hashCode();
result = 31 * result + allTransforms.hashCode();
return result;
}
boolean isDigested() {
return digested;
}
private static Data copyDerefData(Data dereferencedData) {
if (dereferencedData instanceof ApacheData) {
// need to make a copy of the Data
ApacheData ad = (ApacheData)dereferencedData;
XMLSignatureInput xsi = ad.getXMLSignatureInput();
if (xsi.isNodeSet()) {
try {
final Set<Node> s = xsi.getNodeSet();
return new NodeSetData() {
public Iterator<Node> iterator() { return s.iterator(); }
};
} catch (Exception e) {
// LOG a warning
LOG.warn("cannot cache dereferenced data: " + e);
return null;
}
} else if (xsi.isElement()) {
return new DOMSubTreeData
(xsi.getSubNode(), xsi.isExcludeComments());
} else if (xsi.isOctetStream() || xsi.isByteArray()) {
try {
return new OctetStreamData
(xsi.getOctetStream(), xsi.getSourceURI(),
xsi.getMIMEType());
} catch (IOException ioe) {
// LOG a warning
LOG.warn("cannot cache dereferenced data: " + ioe);
return null;
}
}
}
return dereferencedData;
}
}

View File

@@ -0,0 +1,324 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Portions copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* ===========================================================================
*
* (C) Copyright IBM Corp. 2003 All Rights Reserved.
*
* ===========================================================================
*/
/*
* $Id: DOMRetrievalMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.Provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.crypto.Data;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.NodeSetData;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.URIReferenceException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dom.DOMURIReference;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
import javax.xml.parsers.DocumentBuilder;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of RetrievalMethod.
*
*/
public final class DOMRetrievalMethod extends DOMStructure
implements RetrievalMethod, DOMURIReference {
private final List<Transform> transforms;
private String uri;
private String type;
private Attr here;
/**
* Creates a {@code DOMRetrievalMethod} containing the specified
* URIReference and List of Transforms.
*
* @param uri the URI
* @param type the type
* @param transforms a list of {@link Transform}s. The list is defensively
* copied to prevent subsequent modification. May be {@code null}
* or empty.
* @throws IllegalArgumentException if the format of {@code uri} is
* invalid, as specified by Reference's URI attribute in the W3C
* specification for XML-Signature Syntax and Processing
* @throws NullPointerException if {@code uriReference}
* is {@code null}
* @throws ClassCastException if {@code transforms} contains any
* entries that are not of type {@link Transform}
*/
public DOMRetrievalMethod(String uri, String type,
List<? extends Transform> transforms)
{
if (uri == null) {
throw new NullPointerException("uri cannot be null");
}
if (transforms == null || transforms.isEmpty()) {
this.transforms = Collections.emptyList();
} else {
this.transforms = Collections.unmodifiableList(
new ArrayList<>(transforms));
for (int i = 0, size = this.transforms.size(); i < size; i++) {
if (!(this.transforms.get(i) instanceof Transform)) {
throw new ClassCastException
("transforms["+i+"] is not a valid type");
}
}
}
this.uri = uri;
if (!uri.equals("")) {
try {
new URI(uri);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
this.type = type;
}
/**
* Creates a {@code DOMRetrievalMethod} from an element.
*
* @param rmElem a RetrievalMethod element
*/
public DOMRetrievalMethod(Element rmElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
// get URI and Type attributes
uri = DOMUtils.getAttributeValue(rmElem, "URI");
type = DOMUtils.getAttributeValue(rmElem, "Type");
// get here node
here = rmElem.getAttributeNodeNS(null, "URI");
boolean secVal = Utils.secureValidation(context);
// get Transforms, if specified
List<Transform> newTransforms = new ArrayList<>();
Element transformsElem = DOMUtils.getFirstChildElement(rmElem);
if (transformsElem != null) {
String localName = transformsElem.getLocalName();
String namespace = transformsElem.getNamespaceURI();
if (!"Transforms".equals(localName) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " +
namespace + ":" + localName + ", expected Transforms");
}
Element transformElem =
DOMUtils.getFirstChildElement(transformsElem, "Transform", XMLSignature.XMLNS);
while (transformElem != null) {
String name = transformElem.getLocalName();
namespace = transformElem.getNamespaceURI();
if (!"Transform".equals(name) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " +
name + ", expected Transform");
}
newTransforms.add
(new DOMTransform(transformElem, context, provider));
if (secVal && Policy.restrictNumTransforms(newTransforms.size())) {
String error = "A maximum of " + Policy.maxTransforms()
+ " transforms per Reference are allowed when"
+ " secure validation is enabled";
throw new MarshalException(error);
}
transformElem = DOMUtils.getNextSiblingElement(transformElem);
}
}
if (newTransforms.isEmpty()) {
this.transforms = Collections.emptyList();
} else {
this.transforms = Collections.unmodifiableList(newTransforms);
}
}
public String getURI() {
return uri;
}
public String getType() {
return type;
}
public List<Transform> getTransforms() {
return transforms;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element rmElem = DOMUtils.createElement(ownerDoc, "RetrievalMethod",
XMLSignature.XMLNS, dsPrefix);
// add URI and Type attributes
DOMUtils.setAttribute(rmElem, "URI", uri);
DOMUtils.setAttribute(rmElem, "Type", type);
// add Transforms elements
if (!transforms.isEmpty()) {
Element transformsElem = DOMUtils.createElement(ownerDoc,
"Transforms",
XMLSignature.XMLNS,
dsPrefix);
rmElem.appendChild(transformsElem);
for (Transform transform : transforms) {
((DOMTransform)transform).marshal(transformsElem,
dsPrefix, context);
}
}
parent.appendChild(rmElem);
// save here node
here = rmElem.getAttributeNodeNS(null, "URI");
}
public Node getHere() {
return here;
}
public Data dereference(XMLCryptoContext context)
throws URIReferenceException
{
if (context == null) {
throw new NullPointerException("context cannot be null");
}
/*
* If URIDereferencer is specified in context; use it, otherwise use
* built-in.
*/
URIDereferencer deref = context.getURIDereferencer();
if (deref == null) {
deref = DOMURIDereferencer.INSTANCE;
}
Data data = deref.dereference(this, context);
// pass dereferenced data through Transforms
try {
for (Transform transform : transforms) {
data = ((DOMTransform)transform).transform(data, context);
}
} catch (Exception e) {
throw new URIReferenceException(e);
}
// guard against RetrievalMethod loops
if (data instanceof NodeSetData && Utils.secureValidation(context)
&& Policy.restrictRetrievalMethodLoops()) {
NodeSetData nsd = (NodeSetData)data;
Iterator<?> i = nsd.iterator();
if (i.hasNext()) {
Node root = (Node)i.next();
if ("RetrievalMethod".equals(root.getLocalName())) {
throw new URIReferenceException(
"It is forbidden to have one RetrievalMethod point " +
"to another when secure validation is enabled");
}
}
}
return data;
}
public XMLStructure dereferenceAsXMLStructure(XMLCryptoContext context)
throws URIReferenceException
{
DocumentBuilder db = null;
boolean secVal = Utils.secureValidation(context);
ApacheData data = (ApacheData)dereference(context);
try (InputStream is = new ByteArrayInputStream(data.getXMLSignatureInput().getBytes())) {
db = XMLUtils.createDocumentBuilder(false, secVal);
Document doc = db.parse(is);
Element kiElem = doc.getDocumentElement();
if (kiElem.getLocalName().equals("X509Data")
&& XMLSignature.XMLNS.equals(kiElem.getNamespaceURI())) {
return new DOMX509Data(kiElem);
} else {
return null; // unsupported
}
} catch (Exception e) {
throw new URIReferenceException(e);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof RetrievalMethod)) {
return false;
}
RetrievalMethod orm = (RetrievalMethod)obj;
boolean typesEqual = type == null ? orm.getType() == null
: type.equals(orm.getType());
return uri.equals(orm.getURI()) &&
transforms.equals(orm.getTransforms()) && typesEqual;
}
@Override
public int hashCode() {
int result = 17;
if (type != null) {
result = 31 * result + type.hashCode();
}
result = 31 * result + uri.hashCode();
result = 31 * result + transforms.hashCode();
return result;
}
}

View File

@@ -0,0 +1,825 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMSignatureMethod.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.DSAKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import org.w3c.dom.Element;
import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureECDSA;
import com.sun.org.apache.xml.internal.security.utils.JavaUtils;
import org.jcp.xml.dsig.internal.SignerOutputStream;
import sun.security.util.KeyUtil;
/**
* DOM-based abstract implementation of SignatureMethod.
*
*/
public abstract class DOMSignatureMethod extends AbstractDOMSignatureMethod {
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMSignatureMethod.class);
private SignatureMethodParameterSpec params;
private Signature signature;
// see RFC 4051 for these algorithm definitions
static final String RSA_SHA224 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha224";
static final String RSA_SHA256 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
static final String RSA_SHA384 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384";
static final String RSA_SHA512 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
static final String RSA_RIPEMD160 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160";
static final String ECDSA_SHA1 =
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1";
static final String ECDSA_SHA224 =
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224";
static final String ECDSA_SHA256 =
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
static final String ECDSA_SHA384 =
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384";
static final String ECDSA_SHA512 =
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";
static final String DSA_SHA256 =
"http://www.w3.org/2009/xmldsig11#dsa-sha256";
// see RFC 6931 for these algorithm definitions
static final String ECDSA_RIPEMD160 =
"http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160";
static final String RSA_SHA1_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1";
static final String RSA_SHA224_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#sha224-rsa-MGF1";
static final String RSA_SHA256_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1";
static final String RSA_SHA384_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1";
static final String RSA_SHA512_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1";
static final String RSA_RIPEMD160_MGF1 =
"http://www.w3.org/2007/05/xmldsig-more#ripemd160-rsa-MGF1";
/**
* Creates a {@code DOMSignatureMethod}.
*
* @param params the algorithm-specific params (may be {@code null})
* @throws InvalidAlgorithmParameterException if the parameters are not
* appropriate for this signature method
*/
DOMSignatureMethod(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params != null &&
!(params instanceof SignatureMethodParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type SignatureMethodParameterSpec");
}
checkParams((SignatureMethodParameterSpec)params);
this.params = (SignatureMethodParameterSpec)params;
}
/**
* Creates a {@code DOMSignatureMethod} from an element. This ctor
* invokes the {@link #unmarshalParams unmarshalParams} method to
* unmarshal any algorithm-specific input parameters.
*
* @param smElem a SignatureMethod element
*/
DOMSignatureMethod(Element smElem) throws MarshalException {
Element paramsElem = DOMUtils.getFirstChildElement(smElem);
if (paramsElem != null) {
params = unmarshalParams(paramsElem);
}
try {
checkParams(params);
} catch (InvalidAlgorithmParameterException iape) {
throw new MarshalException(iape);
}
}
static SignatureMethod unmarshal(Element smElem) throws MarshalException {
String alg = DOMUtils.getAttributeValue(smElem, "Algorithm");
if (alg.equals(SignatureMethod.RSA_SHA1)) {
return new SHA1withRSA(smElem);
} else if (alg.equals(RSA_SHA224)) {
return new SHA224withRSA(smElem);
} else if (alg.equals(RSA_SHA256)) {
return new SHA256withRSA(smElem);
} else if (alg.equals(RSA_SHA384)) {
return new SHA384withRSA(smElem);
} else if (alg.equals(RSA_SHA512)) {
return new SHA512withRSA(smElem);
} else if (alg.equals(RSA_RIPEMD160)) {
return new RIPEMD160withRSA(smElem);
} else if (alg.equals(RSA_SHA1_MGF1)) {
return new SHA1withRSAandMGF1(smElem);
} else if (alg.equals(RSA_SHA224_MGF1)) {
return new SHA224withRSAandMGF1(smElem);
} else if (alg.equals(RSA_SHA256_MGF1)) {
return new SHA256withRSAandMGF1(smElem);
} else if (alg.equals(RSA_SHA384_MGF1)) {
return new SHA384withRSAandMGF1(smElem);
} else if (alg.equals(RSA_SHA512_MGF1)) {
return new SHA512withRSAandMGF1(smElem);
} else if (alg.equals(RSA_RIPEMD160_MGF1)) {
return new RIPEMD160withRSAandMGF1(smElem);
} else if (alg.equals(SignatureMethod.DSA_SHA1)) {
return new SHA1withDSA(smElem);
} else if (alg.equals(DSA_SHA256)) {
return new SHA256withDSA(smElem);
} else if (alg.equals(ECDSA_SHA1)) {
return new SHA1withECDSA(smElem);
} else if (alg.equals(ECDSA_SHA224)) {
return new SHA224withECDSA(smElem);
} else if (alg.equals(ECDSA_SHA256)) {
return new SHA256withECDSA(smElem);
} else if (alg.equals(ECDSA_SHA384)) {
return new SHA384withECDSA(smElem);
} else if (alg.equals(ECDSA_SHA512)) {
return new SHA512withECDSA(smElem);
} else if (alg.equals(ECDSA_RIPEMD160)) {
return new RIPEMD160withECDSA(smElem);
} else if (alg.equals(SignatureMethod.HMAC_SHA1)) {
return new DOMHMACSignatureMethod.SHA1(smElem);
} else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA224)) {
return new DOMHMACSignatureMethod.SHA224(smElem);
} else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA256)) {
return new DOMHMACSignatureMethod.SHA256(smElem);
} else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA384)) {
return new DOMHMACSignatureMethod.SHA384(smElem);
} else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA512)) {
return new DOMHMACSignatureMethod.SHA512(smElem);
} else if (alg.equals(DOMHMACSignatureMethod.HMAC_RIPEMD160)) {
return new DOMHMACSignatureMethod.RIPEMD160(smElem);
} else {
throw new MarshalException
("unsupported SignatureMethod algorithm: " + alg);
}
}
public final AlgorithmParameterSpec getParameterSpec() {
return params;
}
/**
* Returns an instance of Signature from the specified Provider.
* The algorithm is specified by the {@code getJCAAlgorithm()} method.
*
* @param p the Provider to use
* @return an instance of Signature implementing the algorithm
* specified by {@code getJCAAlgorithm()}
* @throws NoSuchAlgorithmException if the Provider does not support the
* signature algorithm
*/
Signature getSignature(Provider p)
throws NoSuchAlgorithmException {
return (p == null)
? Signature.getInstance(getJCAAlgorithm())
: Signature.getInstance(getJCAAlgorithm(), p);
}
boolean verify(Key key, SignedInfo si, byte[] sig,
XMLValidateContext context)
throws InvalidKeyException, SignatureException, XMLSignatureException
{
if (key == null || si == null || sig == null) {
throw new NullPointerException();
}
if (!(key instanceof PublicKey)) {
throw new InvalidKeyException("key must be PublicKey");
}
checkKeySize(context, key);
if (signature == null) {
Provider p = (Provider) context.getProperty
("org.jcp.xml.dsig.internal.dom.SignatureProvider");
try {
signature = getSignature(p);
} catch (NoSuchAlgorithmException nsae) {
throw new XMLSignatureException(nsae);
}
}
signature.initVerify((PublicKey)key);
LOG.debug("Signature provider: {}", signature.getProvider());
LOG.debug("Verifying with key: {}", key);
LOG.debug("JCA Algorithm: {}", getJCAAlgorithm());
LOG.debug("Signature Bytes length: {}", sig.length);
try (SignerOutputStream outputStream = new SignerOutputStream(signature)) {
((DOMSignedInfo)si).canonicalize(context, outputStream);
Type type = getAlgorithmType();
if (type == Type.DSA) {
int size = ((DSAKey)key).getParams().getQ().bitLength();
return signature.verify(JavaUtils.convertDsaXMLDSIGtoASN1(sig,
size/8));
} else if (type == Type.ECDSA) {
return signature.verify(SignatureECDSA.convertXMLDSIGtoASN1(sig));
} else {
return signature.verify(sig);
}
} catch (IOException ioe) {
throw new XMLSignatureException(ioe);
}
}
/**
* If secure validation mode is enabled, checks that the key size is
* restricted.
*
* @param context the context
* @param key the key to check
* @throws XMLSignatureException if the key size is restricted
*/
private static void checkKeySize(XMLCryptoContext context, Key key)
throws XMLSignatureException {
if (Utils.secureValidation(context)) {
int size = KeyUtil.getKeySize(key);
if (size == -1) {
// key size cannot be determined, so we cannot check against
// restrictions. Note that a DSA key w/o params will be
// rejected later if the certificate chain is validated.
LOG.debug("Size for " +
key.getAlgorithm() + " key cannot be determined");
return;
}
if (Policy.restrictKey(key.getAlgorithm(), size)) {
throw new XMLSignatureException(key.getAlgorithm() +
" keys less than " +
Policy.minKeySize(key.getAlgorithm()) + " bits are" +
" forbidden when secure validation is enabled");
}
}
}
byte[] sign(Key key, SignedInfo si, XMLSignContext context)
throws InvalidKeyException, XMLSignatureException
{
if (key == null || si == null) {
throw new NullPointerException();
}
if (!(key instanceof PrivateKey)) {
throw new InvalidKeyException("key must be PrivateKey");
}
checkKeySize(context, key);
if (signature == null) {
Provider p = (Provider)context.getProperty
("org.jcp.xml.dsig.internal.dom.SignatureProvider");
try {
signature = getSignature(p);
} catch (NoSuchAlgorithmException nsae) {
throw new XMLSignatureException(nsae);
}
}
signature.initSign((PrivateKey)key);
LOG.debug("Signature provider: {}", signature.getProvider());
LOG.debug("JCA Algorithm: {}", getJCAAlgorithm());
try (SignerOutputStream outputStream = new SignerOutputStream(signature)) {
((DOMSignedInfo)si).canonicalize(context, outputStream);
Type type = getAlgorithmType();
if (type == Type.DSA) {
int size = ((DSAKey)key).getParams().getQ().bitLength();
return JavaUtils.convertDsaASN1toXMLDSIG(signature.sign(),
size/8);
} else if (type == Type.ECDSA) {
return SignatureECDSA.convertASN1toXMLDSIG(signature.sign());
} else {
return signature.sign();
}
} catch (SignatureException se) {
throw new XMLSignatureException(se);
} catch (IOException ioe) {
throw new XMLSignatureException(ioe);
}
}
abstract static class AbstractRSAPSSSignatureMethod
extends DOMSignatureMethod {
AbstractRSAPSSSignatureMethod(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
AbstractRSAPSSSignatureMethod(Element dmElem) throws MarshalException {
super(dmElem);
}
abstract public PSSParameterSpec getPSSParameterSpec();
@Override
Signature getSignature(Provider p)
throws NoSuchAlgorithmException {
try {
Signature s = (p == null)
? Signature.getInstance("RSASSA-PSS")
: Signature.getInstance("RSASSA-PSS", p);
try {
s.setParameter(getPSSParameterSpec());
} catch (InvalidAlgorithmParameterException e) {
throw new NoSuchAlgorithmException("Should not happen", e);
}
return s;
} catch (NoSuchAlgorithmException nsae) {
return (p == null)
? Signature.getInstance(getJCAAlgorithm())
: Signature.getInstance(getJCAAlgorithm(), p);
}
}
}
static final class SHA1withRSA extends DOMSignatureMethod {
SHA1withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return SignatureMethod.RSA_SHA1;
}
@Override
String getJCAAlgorithm() {
return "SHA1withRSA";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA224withRSA extends DOMSignatureMethod {
SHA224withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA224withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return RSA_SHA224;
}
String getJCAAlgorithm() {
return "SHA224withRSA";
}
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA256withRSA extends DOMSignatureMethod {
SHA256withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return RSA_SHA256;
}
String getJCAAlgorithm() {
return "SHA256withRSA";
}
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA384withRSA extends DOMSignatureMethod {
SHA384withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA384withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return RSA_SHA384;
}
String getJCAAlgorithm() {
return "SHA384withRSA";
}
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA512withRSA extends DOMSignatureMethod {
SHA512withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA512withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return RSA_SHA512;
}
String getJCAAlgorithm() {
return "SHA512withRSA";
}
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class RIPEMD160withRSA extends DOMSignatureMethod {
RIPEMD160withRSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
RIPEMD160withRSA(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_RIPEMD160;
}
@Override
String getJCAAlgorithm() {
return "RIPEMD160withRSA";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA1withRSAandMGF1 extends AbstractRSAPSSSignatureMethod {
private static PSSParameterSpec spec
= new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1,
20, PSSParameterSpec.TRAILER_FIELD_BC);
SHA1withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_SHA1_MGF1;
}
@Override
public PSSParameterSpec getPSSParameterSpec() {
return spec;
}
@Override
String getJCAAlgorithm() {
return "SHA1withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA224withRSAandMGF1 extends AbstractRSAPSSSignatureMethod {
private static PSSParameterSpec spec
= new PSSParameterSpec("SHA-224", "MGF1", MGF1ParameterSpec.SHA224,
28, PSSParameterSpec.TRAILER_FIELD_BC);
SHA224withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA224withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_SHA224_MGF1;
}
@Override
public PSSParameterSpec getPSSParameterSpec() {
return spec;
}
@Override
String getJCAAlgorithm() {
return "SHA224withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA256withRSAandMGF1 extends AbstractRSAPSSSignatureMethod {
private static PSSParameterSpec spec
= new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
32, PSSParameterSpec.TRAILER_FIELD_BC);
SHA256withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_SHA256_MGF1;
}
@Override
public PSSParameterSpec getPSSParameterSpec() {
return spec;
}
@Override
String getJCAAlgorithm() {
return "SHA256withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA384withRSAandMGF1 extends AbstractRSAPSSSignatureMethod {
private static PSSParameterSpec spec
= new PSSParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384,
48, PSSParameterSpec.TRAILER_FIELD_BC);
SHA384withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA384withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_SHA384_MGF1;
}
@Override
public PSSParameterSpec getPSSParameterSpec() {
return spec;
}
@Override
String getJCAAlgorithm() {
return "SHA384withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA512withRSAandMGF1 extends AbstractRSAPSSSignatureMethod {
private static PSSParameterSpec spec
= new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512,
64, PSSParameterSpec.TRAILER_FIELD_BC);
SHA512withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA512withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_SHA512_MGF1;
}
@Override
public PSSParameterSpec getPSSParameterSpec() {
return spec;
}
@Override
String getJCAAlgorithm() {
return "SHA512withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class RIPEMD160withRSAandMGF1 extends DOMSignatureMethod {
RIPEMD160withRSAandMGF1(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
RIPEMD160withRSAandMGF1(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return RSA_RIPEMD160_MGF1;
}
@Override
String getJCAAlgorithm() {
return "RIPEMD160withRSAandMGF1";
}
@Override
Type getAlgorithmType() {
return Type.RSA;
}
}
static final class SHA1withDSA extends DOMSignatureMethod {
SHA1withDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1withDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return SignatureMethod.DSA_SHA1;
}
String getJCAAlgorithm() {
return "SHA1withDSA";
}
Type getAlgorithmType() {
return Type.DSA;
}
}
static final class SHA256withDSA extends DOMSignatureMethod {
SHA256withDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256withDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return DSA_SHA256;
}
String getJCAAlgorithm() {
return "SHA256withDSA";
}
Type getAlgorithmType() {
return Type.DSA;
}
}
static final class SHA1withECDSA extends DOMSignatureMethod {
SHA1withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA1withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return ECDSA_SHA1;
}
String getJCAAlgorithm() {
return "SHA1withECDSA";
}
Type getAlgorithmType() {
return Type.ECDSA;
}
}
static final class SHA224withECDSA extends DOMSignatureMethod {
SHA224withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA224withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return ECDSA_SHA224;
}
@Override
String getJCAAlgorithm() {
return "SHA224withECDSA";
}
@Override
Type getAlgorithmType() {
return Type.ECDSA;
}
}
static final class SHA256withECDSA extends DOMSignatureMethod {
SHA256withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA256withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return ECDSA_SHA256;
}
String getJCAAlgorithm() {
return "SHA256withECDSA";
}
Type getAlgorithmType() {
return Type.ECDSA;
}
}
static final class SHA384withECDSA extends DOMSignatureMethod {
SHA384withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA384withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return ECDSA_SHA384;
}
String getJCAAlgorithm() {
return "SHA384withECDSA";
}
Type getAlgorithmType() {
return Type.ECDSA;
}
}
static final class SHA512withECDSA extends DOMSignatureMethod {
SHA512withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
SHA512withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
public String getAlgorithm() {
return ECDSA_SHA512;
}
String getJCAAlgorithm() {
return "SHA512withECDSA";
}
Type getAlgorithmType() {
return Type.ECDSA;
}
}
static final class RIPEMD160withECDSA extends DOMSignatureMethod {
RIPEMD160withECDSA(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
super(params);
}
RIPEMD160withECDSA(Element dmElem) throws MarshalException {
super(dmElem);
}
@Override
public String getAlgorithm() {
return ECDSA_RIPEMD160;
}
@Override
String getJCAAlgorithm() {
return "RIPEMD160withECDSA";
}
@Override
Type getAlgorithmType() {
return Type.ECDSA;
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMSignatureProperties.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import java.util.*;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of SignatureProperties.
*
*/
public final class DOMSignatureProperties extends DOMStructure
implements SignatureProperties {
private final String id;
private final List<SignatureProperty> properties;
/**
* Creates a {@code DOMSignatureProperties} from the specified
* parameters.
*
* @param properties a list of one or more {@link SignatureProperty}s. The
* list is defensively copied to protect against subsequent modification.
* @param id the Id (may be {@code null})
* @throws ClassCastException if {@code properties} contains any
* entries that are not of type {@link SignatureProperty}
* @throws IllegalArgumentException if {@code properties} is empty
* @throws NullPointerException if {@code properties}
*/
public DOMSignatureProperties(List<? extends SignatureProperty> properties,
String id)
{
if (properties == null) {
throw new NullPointerException("properties cannot be null");
} else if (properties.isEmpty()) {
throw new IllegalArgumentException("properties cannot be empty");
} else {
this.properties = Collections.unmodifiableList(
new ArrayList<>(properties));
for (int i = 0, size = this.properties.size(); i < size; i++) {
if (!(this.properties.get(i) instanceof SignatureProperty)) {
throw new ClassCastException
("properties["+i+"] is not a valid type");
}
}
}
this.id = id;
}
/**
* Creates a {@code DOMSignatureProperties} from an element.
*
* @param propsElem a SignatureProperties element
* @throws MarshalException if a marshalling error occurs
*/
public DOMSignatureProperties(Element propsElem)
throws MarshalException
{
// unmarshal attributes
Attr attr = propsElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
id = attr.getValue();
propsElem.setIdAttributeNode(attr, true);
} else {
id = null;
}
List<SignatureProperty> newProperties = new ArrayList<>();
Node firstChild = propsElem.getFirstChild();
while (firstChild != null) {
if (firstChild.getNodeType() == Node.ELEMENT_NODE) {
String name = firstChild.getLocalName();
String namespace = firstChild.getNamespaceURI();
if (!"SignatureProperty".equals(name) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " + namespace + ":" + name +
", expected SignatureProperty");
}
newProperties.add(new DOMSignatureProperty((Element)firstChild));
}
firstChild = firstChild.getNextSibling();
}
if (newProperties.isEmpty()) {
throw new MarshalException("properties cannot be empty");
} else {
this.properties = Collections.unmodifiableList(newProperties);
}
}
public List<SignatureProperty> getProperties() {
return properties;
}
public String getId() {
return id;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element propsElem = DOMUtils.createElement(ownerDoc,
"SignatureProperties",
XMLSignature.XMLNS,
dsPrefix);
// set attributes
DOMUtils.setAttributeID(propsElem, "Id", id);
// create and append any properties
for (SignatureProperty property : properties) {
((DOMSignatureProperty)property).marshal(propsElem, dsPrefix,
context);
}
parent.appendChild(propsElem);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SignatureProperties)) {
return false;
}
SignatureProperties osp = (SignatureProperties)o;
boolean idsEqual = id == null ? osp.getId() == null
: id.equals(osp.getId());
return properties.equals(osp.getProperties()) && idsEqual;
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
result = 31 * result + properties.hashCode();
return result;
}
}

View File

@@ -0,0 +1,214 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMSignatureProperty.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import java.util.*;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of SignatureProperty.
*
*/
public final class DOMSignatureProperty extends DOMStructure
implements SignatureProperty {
private final String id;
private final String target;
private final List<XMLStructure> content;
/**
* Creates a {@code SignatureProperty} from the specified parameters.
*
* @param content a list of one or more {@link XMLStructure}s. The list
* is defensively copied to protect against subsequent modification.
* @param target the target URI
* @param id the Id (may be {@code null})
* @throws ClassCastException if {@code content} contains any
* entries that are not of type {@link XMLStructure}
* @throws IllegalArgumentException if {@code content} is empty
* @throws NullPointerException if {@code content} or
* {@code target} is {@code null}
*/
public DOMSignatureProperty(List<? extends XMLStructure> content,
String target, String id)
{
if (target == null) {
throw new NullPointerException("target cannot be null");
} else if (content == null) {
throw new NullPointerException("content cannot be null");
} else if (content.isEmpty()) {
throw new IllegalArgumentException("content cannot be empty");
} else {
this.content = Collections.unmodifiableList(
new ArrayList<>(content));
for (int i = 0, size = this.content.size(); i < size; i++) {
if (!(this.content.get(i) instanceof XMLStructure)) {
throw new ClassCastException
("content["+i+"] is not a valid type");
}
}
}
this.target = target;
this.id = id;
}
/**
* Creates a {@code DOMSignatureProperty} from an element.
*
* @param propElem a SignatureProperty element
*/
public DOMSignatureProperty(Element propElem)
throws MarshalException
{
// unmarshal attributes
target = DOMUtils.getAttributeValue(propElem, "Target");
if (target == null) {
throw new MarshalException("target cannot be null");
}
Attr attr = propElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
id = attr.getValue();
propElem.setIdAttributeNode(attr, true);
} else {
id = null;
}
List<XMLStructure> newContent = new ArrayList<>();
Node firstChild = propElem.getFirstChild();
while (firstChild != null) {
newContent.add(new javax.xml.crypto.dom.DOMStructure(firstChild));
firstChild = firstChild.getNextSibling();
}
if (newContent.isEmpty()) {
throw new MarshalException("content cannot be empty");
} else {
this.content = Collections.unmodifiableList(newContent);
}
}
public List<XMLStructure> getContent() {
return content;
}
public String getId() {
return id;
}
public String getTarget() {
return target;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element propElem = DOMUtils.createElement(ownerDoc, "SignatureProperty",
XMLSignature.XMLNS, dsPrefix);
// set attributes
DOMUtils.setAttributeID(propElem, "Id", id);
DOMUtils.setAttribute(propElem, "Target", target);
// create and append any elements and mixed content
for (XMLStructure property : content) {
DOMUtils.appendChild(propElem,
((javax.xml.crypto.dom.DOMStructure)property).getNode());
}
parent.appendChild(propElem);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SignatureProperty)) {
return false;
}
SignatureProperty osp = (SignatureProperty)o;
boolean idsEqual = id == null ? osp.getId() == null
: id.equals(osp.getId());
@SuppressWarnings("unchecked")
List<XMLStructure> ospContent = osp.getContent();
return equalsContent(ospContent) &&
target.equals(osp.getTarget()) && idsEqual;
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
result = 31 * result + target.hashCode();
result = 31 * result + content.hashCode();
return result;
}
private boolean equalsContent(List<XMLStructure> otherContent) {
int osize = otherContent.size();
if (content.size() != osize) {
return false;
}
for (int i = 0; i < osize; i++) {
XMLStructure oxs = otherContent.get(i);
XMLStructure xs = content.get(i);
if (oxs instanceof javax.xml.crypto.dom.DOMStructure) {
if (!(xs instanceof javax.xml.crypto.dom.DOMStructure)) {
return false;
}
Node onode = ((javax.xml.crypto.dom.DOMStructure)oxs).getNode();
Node node = ((javax.xml.crypto.dom.DOMStructure)xs).getNode();
if (!DOMUtils.nodesEqual(node, onode)) {
return false;
}
} else {
if (!(xs.equals(oxs))) {
return false;
}
}
}
return true;
}
}

View File

@@ -0,0 +1,303 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMSignedInfo.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.security.Provider;
import java.util.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
/**
* DOM-based implementation of SignedInfo.
*
*/
public final class DOMSignedInfo extends DOMStructure implements SignedInfo {
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMSignedInfo.class);
private List<Reference> references;
private CanonicalizationMethod canonicalizationMethod;
private SignatureMethod signatureMethod;
private String id;
private Document ownerDoc;
private Element localSiElem;
private InputStream canonData;
/**
* Creates a {@code DOMSignedInfo} from the specified parameters. Use
* this constructor when the {@code Id} is not specified.
*
* @param cm the canonicalization method
* @param sm the signature method
* @param references the list of references. The list is copied.
* @throws NullPointerException if
* {@code cm}, {@code sm}, or {@code references} is
* {@code null}
* @throws IllegalArgumentException if {@code references} is empty
* @throws ClassCastException if any of the references are not of
* type {@code Reference}
*/
public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm,
List<? extends Reference> references) {
if (cm == null || sm == null || references == null) {
throw new NullPointerException();
}
this.canonicalizationMethod = cm;
this.signatureMethod = sm;
this.references = Collections.unmodifiableList(
new ArrayList<>(references));
if (this.references.isEmpty()) {
throw new IllegalArgumentException("list of references must " +
"contain at least one entry");
}
for (int i = 0, size = this.references.size(); i < size; i++) {
Object obj = this.references.get(i);
if (!(obj instanceof Reference)) {
throw new ClassCastException("list of references contains " +
"an illegal type");
}
}
}
/**
* Creates a {@code DOMSignedInfo} from the specified parameters.
*
* @param cm the canonicalization method
* @param sm the signature method
* @param references the list of references. The list is copied.
* @param id an optional identifer that will allow this
* {@code SignedInfo} to be referenced by other signatures and
* objects
* @throws NullPointerException if {@code cm}, {@code sm},
* or {@code references} is {@code null}
* @throws IllegalArgumentException if {@code references} is empty
* @throws ClassCastException if any of the references are not of
* type {@code Reference}
*/
public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm,
List<? extends Reference> references, String id) {
this(cm, sm, references);
this.id = id;
}
/**
* Creates a {@code DOMSignedInfo} from an element.
*
* @param siElem a SignedInfo element
*/
public DOMSignedInfo(Element siElem, XMLCryptoContext context, Provider provider)
throws MarshalException {
localSiElem = siElem;
ownerDoc = siElem.getOwnerDocument();
// get Id attribute, if specified
id = DOMUtils.getAttributeValue(siElem, "Id");
// unmarshal CanonicalizationMethod
Element cmElem = DOMUtils.getFirstChildElement(siElem,
"CanonicalizationMethod",
XMLSignature.XMLNS);
canonicalizationMethod = new DOMCanonicalizationMethod(cmElem, context,
provider);
// unmarshal SignatureMethod
Element smElem = DOMUtils.getNextSiblingElement(cmElem,
"SignatureMethod",
XMLSignature.XMLNS);
signatureMethod = DOMSignatureMethod.unmarshal(smElem);
boolean secVal = Utils.secureValidation(context);
String signatureMethodAlgorithm = signatureMethod.getAlgorithm();
if (secVal && Policy.restrictAlg(signatureMethodAlgorithm)) {
throw new MarshalException(
"It is forbidden to use algorithm " + signatureMethodAlgorithm +
" when secure validation is enabled"
);
}
// unmarshal References
ArrayList<Reference> refList = new ArrayList<>(5);
Element refElem = DOMUtils.getNextSiblingElement(smElem, "Reference", XMLSignature.XMLNS);
refList.add(new DOMReference(refElem, context, provider));
refElem = DOMUtils.getNextSiblingElement(refElem);
while (refElem != null) {
String name = refElem.getLocalName();
String namespace = refElem.getNamespaceURI();
if (!"Reference".equals(name) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " +
namespace + ":" + name + ", expected Reference");
}
refList.add(new DOMReference(refElem, context, provider));
if (secVal && Policy.restrictNumReferences(refList.size())) {
String error = "A maxiumum of " + Policy.maxReferences()
+ " references per Manifest are allowed when"
+ " secure validation is enabled";
throw new MarshalException(error);
}
refElem = DOMUtils.getNextSiblingElement(refElem);
}
references = Collections.unmodifiableList(refList);
}
public CanonicalizationMethod getCanonicalizationMethod() {
return canonicalizationMethod;
}
public SignatureMethod getSignatureMethod() {
return signatureMethod;
}
public String getId() {
return id;
}
public List<Reference> getReferences() {
return references;
}
public InputStream getCanonicalizedData() {
return canonData;
}
public void canonicalize(XMLCryptoContext context, ByteArrayOutputStream bos)
throws XMLSignatureException {
if (context == null) {
throw new NullPointerException("context cannot be null");
}
DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true);
try (OutputStream os = new UnsyncBufferedOutputStream(bos)) {
((DOMCanonicalizationMethod)
canonicalizationMethod).canonicalize(subTree, context, os);
os.flush();
byte[] signedInfoBytes = bos.toByteArray();
// this whole block should only be done if LOGging is enabled
if (LOG.isDebugEnabled()) {
LOG.debug("Canonicalized SignedInfo:");
StringBuilder sb = new StringBuilder(signedInfoBytes.length);
for (int i = 0; i < signedInfoBytes.length; i++) {
sb.append((char)signedInfoBytes[i]);
}
LOG.debug(sb.toString());
LOG.debug("Data to be signed/verified:" + XMLUtils.encodeToString(signedInfoBytes));
}
this.canonData = new ByteArrayInputStream(signedInfoBytes);
} catch (TransformException te) {
throw new XMLSignatureException(te);
} catch (IOException e) {
LOG.debug(e.getMessage(), e);
// Impossible
}
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
ownerDoc = DOMUtils.getOwnerDocument(parent);
Element siElem = DOMUtils.createElement(ownerDoc, "SignedInfo",
XMLSignature.XMLNS, dsPrefix);
// create and append CanonicalizationMethod element
DOMCanonicalizationMethod dcm =
(DOMCanonicalizationMethod)canonicalizationMethod;
dcm.marshal(siElem, dsPrefix, context);
// create and append SignatureMethod element
((DOMStructure)signatureMethod).marshal(siElem, dsPrefix, context);
// create and append Reference elements
for (Reference reference : references) {
((DOMReference)reference).marshal(siElem, dsPrefix, context);
}
// append Id attribute
DOMUtils.setAttributeID(siElem, "Id", id);
parent.appendChild(siElem);
localSiElem = siElem;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SignedInfo)) {
return false;
}
SignedInfo osi = (SignedInfo)o;
boolean idEqual = id == null ? osi.getId() == null
: id.equals(osi.getId());
return canonicalizationMethod.equals(osi.getCanonicalizationMethod())
&& signatureMethod.equals(osi.getSignatureMethod()) &&
references.equals(osi.getReferences()) && idEqual;
}
@SuppressWarnings("unchecked")
public static List<Reference> getSignedInfoReferences(SignedInfo si) {
return si.getReferences();
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
result = 31 * result + canonicalizationMethod.hashCode();
result = 31 * result + signatureMethod.hashCode();
result = 31 * result + references.hashCode();
return result;
}
}

View File

@@ -0,0 +1,52 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMStructure.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMCryptoContext;
import org.w3c.dom.Node;
/**
* DOM-based abstract implementation of XMLStructure.
*
*/
public abstract class DOMStructure implements XMLStructure {
public final boolean isFeatureSupported(String feature) {
if (feature == null) {
throw new NullPointerException();
} else {
return false;
}
}
public abstract void marshal(Node parent, String dsPrefix,
DOMCryptoContext context) throws MarshalException;
}

View File

@@ -0,0 +1,182 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id$
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.NodeSetData;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* This is a subtype of NodeSetData that represents a dereferenced
* same-document URI as the root of a subdocument. The main reason is
* for efficiency and performance, as some transforms can operate
* directly on the subdocument and there is no need to convert it
* first to an XPath node-set.
*/
public class DOMSubTreeData implements NodeSetData {
private boolean excludeComments;
private Node root;
public DOMSubTreeData(Node root, boolean excludeComments) {
this.root = root;
this.excludeComments = excludeComments;
}
@Override
public Iterator<Node> iterator() {
return new DelayedNodeIterator(root, excludeComments);
}
public Node getRoot() {
return root;
}
public boolean excludeComments() {
return excludeComments;
}
/**
* This is an Iterator that contains a backing node-set that is
* not populated until the caller first attempts to advance the iterator.
*/
static class DelayedNodeIterator implements Iterator<Node> {
private Node root;
private List<Node> nodeSet;
private ListIterator<Node> li;
private boolean withComments;
DelayedNodeIterator(Node root, boolean excludeComments) {
this.root = root;
this.withComments = !excludeComments;
}
public boolean hasNext() {
if (nodeSet == null) {
nodeSet = dereferenceSameDocumentURI(root);
li = nodeSet.listIterator();
}
return li.hasNext();
}
public Node next() {
if (nodeSet == null) {
nodeSet = dereferenceSameDocumentURI(root);
li = nodeSet.listIterator();
}
if (li.hasNext()) {
return li.next();
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Dereferences a same-document URI fragment.
*
* @param node the node (document or element) referenced by the
* URI fragment. If null, returns an empty set.
* @return a set of nodes (minus any comment nodes)
*/
private List<Node> dereferenceSameDocumentURI(Node node) {
List<Node> nodes = new ArrayList<>();
if (node != null) {
nodeSetMinusCommentNodes(node, nodes, null);
}
return nodes;
}
/**
* Recursively traverses the subtree, and returns an XPath-equivalent
* node-set of all nodes traversed, excluding any comment nodes,
* if specified.
*
* @param node the node to traverse
* @param nodeSet the set of nodes traversed so far
* @param the previous sibling node
*/
@SuppressWarnings("fallthrough")
private void nodeSetMinusCommentNodes(Node node, List<Node> nodeSet,
Node prevSibling)
{
switch (node.getNodeType()) {
case Node.ELEMENT_NODE :
NamedNodeMap attrs = node.getAttributes();
if (attrs != null) {
for (int i = 0, len = attrs.getLength(); i < len; i++) {
nodeSet.add(attrs.item(i));
}
}
nodeSet.add(node);
Node pSibling = null;
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling()) {
nodeSetMinusCommentNodes(child, nodeSet, pSibling);
pSibling = child;
}
break;
case Node.DOCUMENT_NODE :
pSibling = null;
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling()) {
nodeSetMinusCommentNodes(child, nodeSet, pSibling);
pSibling = child;
}
break;
case Node.TEXT_NODE :
case Node.CDATA_SECTION_NODE:
// emulate XPath which only returns the first node in
// contiguous text/cdata nodes
if (prevSibling != null &&
(prevSibling.getNodeType() == Node.TEXT_NODE ||
prevSibling.getNodeType() == Node.CDATA_SECTION_NODE)) {
return;
}
nodeSet.add(node);
break;
case Node.PROCESSING_INSTRUCTION_NODE :
nodeSet.add(node);
break;
case Node.COMMENT_NODE:
if (withComments) {
nodeSet.add(node);
}
}
}
}
}

View File

@@ -0,0 +1,227 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMTransform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.spec.AlgorithmParameterSpec;
import javax.xml.crypto.Data;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.TransformException;
import javax.xml.crypto.dsig.TransformService;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based abstract implementation of Transform.
*
*/
public class DOMTransform extends DOMStructure implements Transform {
protected TransformService spi;
/**
* Creates a {@code DOMTransform}.
*
* @param spi the TransformService
*/
public DOMTransform(TransformService spi) {
this.spi = spi;
}
/**
* Creates a {@code DOMTransform} from an element. It unmarshals any
* algorithm-specific input parameters.
*
* @param transElem a Transform element
*/
public DOMTransform(Element transElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
String algorithm = DOMUtils.getAttributeValue(transElem, "Algorithm");
if (provider == null) {
try {
spi = TransformService.getInstance(algorithm, "DOM");
} catch (NoSuchAlgorithmException e1) {
throw new MarshalException(e1);
}
} else {
try {
spi = TransformService.getInstance(algorithm, "DOM", provider);
} catch (NoSuchAlgorithmException nsae) {
try {
spi = TransformService.getInstance(algorithm, "DOM");
} catch (NoSuchAlgorithmException e2) {
throw new MarshalException(e2);
}
}
}
try {
spi.init(new javax.xml.crypto.dom.DOMStructure(transElem), context);
} catch (InvalidAlgorithmParameterException iape) {
throw new MarshalException(iape);
}
}
public final AlgorithmParameterSpec getParameterSpec() {
return spi.getParameterSpec();
}
public final String getAlgorithm() {
return spi.getAlgorithm();
}
/**
* This method marshals any algorithm-specific parameters.
*/
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element transformElem = null;
if (parent.getLocalName().equals("Transforms")) {
transformElem = DOMUtils.createElement(ownerDoc, "Transform",
XMLSignature.XMLNS,
dsPrefix);
} else {
transformElem = DOMUtils.createElement(ownerDoc,
"CanonicalizationMethod",
XMLSignature.XMLNS,
dsPrefix);
}
DOMUtils.setAttribute(transformElem, "Algorithm", getAlgorithm());
spi.marshalParams(new javax.xml.crypto.dom.DOMStructure(transformElem),
context);
parent.appendChild(transformElem);
}
/**
* Transforms the specified data using the underlying transform algorithm.
*
* @param data the data to be transformed
* @param xc the {@code XMLCryptoContext} containing
* additional context (may be {@code null} if not applicable)
* @return the transformed data
* @throws NullPointerException if {@code data} is {@code null}
* @throws XMLSignatureException if an unexpected error occurs while
* executing the transform
*/
public Data transform(Data data, XMLCryptoContext xc)
throws TransformException
{
return spi.transform(data, xc);
}
/**
* Transforms the specified data using the underlying transform algorithm.
*
* @param data the data to be transformed
* @param xc the {@code XMLCryptoContext} containing
* additional context (may be {@code null} if not applicable)
* @param os the {@code OutputStream} that should be used to write
* the transformed data to
* @return the transformed data
* @throws NullPointerException if {@code data} is {@code null}
* @throws XMLSignatureException if an unexpected error occurs while
* executing the transform
*/
public Data transform(Data data, XMLCryptoContext xc, OutputStream os)
throws TransformException
{
return spi.transform(data, xc, os);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Transform)) {
return false;
}
Transform otransform = (Transform)o;
return getAlgorithm().equals(otransform.getAlgorithm()) &&
DOMUtils.paramsEqual(getParameterSpec(),
otransform.getParameterSpec());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + getAlgorithm().hashCode();
AlgorithmParameterSpec spec = getParameterSpec();
if (spec != null) {
result = 31 * result + spec.hashCode();
}
return result;
}
/**
* Transforms the specified data using the underlying transform algorithm.
* This method invokes the {@link #marshal marshal} method and passes it
* the specified {@code DOMSignContext} before transforming the data.
*
* @param data the data to be transformed
* @param sc the {@code XMLCryptoContext} containing
* additional context (may be {@code null} if not applicable)
* @param context the marshalling context
* @return the transformed data
* @throws MarshalException if an exception occurs while marshalling
* @throws NullPointerException if {@code data} or {@code context}
* is {@code null}
* @throws XMLSignatureException if an unexpected error occurs while
* executing the transform
*/
Data transform(Data data, XMLCryptoContext xc, DOMSignContext context)
throws MarshalException, TransformException
{
marshal(context.getParent(),
DOMUtils.getSignaturePrefix(context), context);
return transform(data, xc);
}
}

View File

@@ -0,0 +1,155 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMURIDereferencer.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.Init;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.*;
import java.net.URI;
/**
* DOM-based implementation of URIDereferencer.
*
*/
public final class DOMURIDereferencer implements URIDereferencer {
static final URIDereferencer INSTANCE = new DOMURIDereferencer();
private DOMURIDereferencer() {
// need to call com.sun.org.apache.xml.internal.security.Init.init()
// before calling any apache security code
Init.init();
}
public Data dereference(URIReference uriRef, XMLCryptoContext context)
throws URIReferenceException {
if (uriRef == null) {
throw new NullPointerException("uriRef cannot be null");
}
if (context == null) {
throw new NullPointerException("context cannot be null");
}
DOMURIReference domRef = (DOMURIReference) uriRef;
Attr uriAttr = (Attr) domRef.getHere();
String uri = uriRef.getURI();
DOMCryptoContext dcc = (DOMCryptoContext) context;
String baseURI = context.getBaseURI();
boolean secVal = Utils.secureValidation(context);
if (secVal) {
try {
if (Policy.restrictReferenceUriScheme(uri)) {
throw new URIReferenceException(
"URI " + uri + " is forbidden when secure validation is enabled");
}
if (uri != null && !uri.isEmpty() && uri.charAt(0) != '#' && URI.create(uri).getScheme() == null) {
// beseURI will be used to dereference a relative uri
try {
if (Policy.restrictReferenceUriScheme(baseURI)) {
throw new URIReferenceException(
"Base URI " + baseURI + " is forbidden when secure validation is enabled");
}
} catch (IllegalArgumentException e) { // thrown by Policy.restrictReferenceUriScheme
throw new URIReferenceException("Invalid base URI " + baseURI);
}
}
} catch (IllegalArgumentException e) { // thrown by Policy.restrictReferenceUriScheme or URI.create
throw new URIReferenceException("Invalid URI " + uri);
}
}
// Check if same-document URI and already registered on the context
if (uri != null && uri.length() != 0 && uri.charAt(0) == '#') {
String id = uri.substring(1);
if (id.startsWith("xpointer(id(")) {
int i1 = id.indexOf('\'');
int i2 = id.indexOf('\'', i1+1);
id = id.substring(i1+1, i2);
}
// check if element is registered by Id
Node referencedElem = uriAttr.getOwnerDocument().getElementById(id);
if (referencedElem == null) {
// see if element is registered in DOMCryptoContext
referencedElem = dcc.getElementById(id);
}
if (referencedElem != null) {
if (secVal && Policy.restrictDuplicateIds()) {
Element start = referencedElem.getOwnerDocument().getDocumentElement();
if (!XMLUtils.protectAgainstWrappingAttack(start, (Element)referencedElem, id)) {
String error = "Multiple Elements with the same ID "
+ id + " detected when secure validation"
+ " is enabled";
throw new URIReferenceException(error);
}
}
XMLSignatureInput result = new XMLSignatureInput(referencedElem);
result.setSecureValidation(secVal);
if (!uri.substring(1).startsWith("xpointer(id(")) {
result.setExcludeComments(true);
}
result.setMIMEType("text/xml");
if (baseURI != null && baseURI.length() > 0) {
result.setSourceURI(baseURI.concat(uriAttr.getNodeValue()));
} else {
result.setSourceURI(uriAttr.getNodeValue());
}
return new ApacheNodeSetData(result);
}
}
try {
ResourceResolver apacheResolver =
ResourceResolver.getInstance(uriAttr, baseURI, secVal);
XMLSignatureInput in = apacheResolver.resolve(uriAttr, baseURI, secVal);
if (in.isOctetStream()) {
return new ApacheOctetStreamData(in);
} else {
return new ApacheNodeSetData(in);
}
} catch (Exception e) {
throw new URIReferenceException(e);
}
}
}

View File

@@ -0,0 +1,520 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMUtils.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.util.*;
import java.security.spec.AlgorithmParameterSpec;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.XMLConstants;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.*;
/**
* Useful static DOM utility methods.
*
*/
public final class DOMUtils {
// class cannot be instantiated
private DOMUtils() {}
/**
* Returns the owner document of the specified node.
*
* @param node the node
* @return the owner document
*/
public static Document getOwnerDocument(Node node) {
if (node.getNodeType() == Node.DOCUMENT_NODE) {
return (Document)node;
} else {
return node.getOwnerDocument();
}
}
/**
* Create a QName string from a prefix and local name.
*
* @param prefix The prefix, if any. Can be either null or empty.
* @param localName The local name.
*
* @return The string for the qName, for example, "xsd:element".
*/
public static String getQNameString(String prefix, String localName) {
String qName = prefix == null || prefix.length() == 0
? localName : prefix + ":" + localName;
return qName;
}
/**
* Creates an element in the specified namespace, with the specified tag
* and namespace prefix.
*
* @param doc the owner document
* @param tag the tag
* @param nsURI the namespace URI
* @param prefix the namespace prefix
* @return the newly created element
*/
public static Element createElement(Document doc, String tag,
String nsURI, String prefix)
{
String qName = prefix == null || prefix.length() == 0
? tag : prefix + ":" + tag;
return doc.createElementNS(nsURI, qName);
}
/**
* Sets an element's attribute (using DOM level 2) with the
* specified value and namespace prefix.
*
* @param elem the element to set the attribute on
* @param name the name of the attribute
* @param value the attribute value. If null, no attribute is set.
*/
public static void setAttribute(Element elem, String name, String value) {
if (value == null) {
return;
}
elem.setAttributeNS(null, name, value);
}
/**
* Sets an element's attribute (using DOM level 2) with the
* specified value and namespace prefix AND registers the ID value with
* the specified element. This is for resolving same-document
* ID references.
*
* @param elem the element to set the attribute on
* @param name the name of the attribute
* @param value the attribute value. If null, no attribute is set.
*/
public static void setAttributeID(Element elem, String name, String value) {
if (value == null) {
return;
}
elem.setAttributeNS(null, name, value);
elem.setIdAttributeNS(null, name, true);
}
/**
* Returns the first child element of the specified node, or null if there
* is no such element.
*
* @param node the node
* @return the first child element of the specified node, or null if there
* is no such element
* @throws NullPointerException if {@code node == null}
*/
public static Element getFirstChildElement(Node node) {
Node child = node.getFirstChild();
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
child = child.getNextSibling();
}
return (Element)child;
}
/**
* Returns the first child element of the specified node and checks that
* the local name is equal to {@code localName}.
*
* @param node the node
* @return the first child element of the specified node
* @throws NullPointerException if {@code node == null}
* @throws MarshalException if no such element or the local name is not
* equal to {@code localName}
*/
@Deprecated
public static Element getFirstChildElement(Node node, String localName)
throws MarshalException
{
return verifyElement(getFirstChildElement(node), localName);
}
/**
* Returns the first child element of the specified node and checks that
* the local name is equal to {@code localName} and the namespace is equal to
* {@code namespaceURI}
*
* @param node the node
* @return the first child element of the specified node
* @throws NullPointerException if {@code node == null}
* @throws MarshalException if no such element or the local name is not
* equal to {@code localName}
*/
public static Element getFirstChildElement(Node node, String localName, String namespaceURI)
throws MarshalException
{
return verifyElement(getFirstChildElement(node), localName, namespaceURI);
}
private static Element verifyElement(Element elem, String localName)
throws MarshalException
{
if (elem == null) {
throw new MarshalException("Missing " + localName + " element");
}
String name = elem.getLocalName();
if (!name.equals(localName)) {
throw new MarshalException("Invalid element name: " +
name + ", expected " + localName);
}
return elem;
}
private static Element verifyElement(Element elem, String localName, String namespaceURI)
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)) {
throw new MarshalException("Invalid element name: " +
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);
}
return elem;
}
/**
* Returns the last child element of the specified node, or null if there
* is no such element.
*
* @param node the node
* @return the last child element of the specified node, or null if there
* is no such element
* @throws NullPointerException if {@code node == null}
*/
public static Element getLastChildElement(Node node) {
Node child = node.getLastChild();
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
child = child.getPreviousSibling();
}
return (Element)child;
}
/**
* Returns the next sibling element of the specified node, or null if there
* is no such element.
*
* @param node the node
* @return the next sibling element of the specified node, or null if there
* is no such element
* @throws NullPointerException if {@code node == null}
*/
public static Element getNextSiblingElement(Node node) {
Node sibling = node.getNextSibling();
while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) {
sibling = sibling.getNextSibling();
}
return (Element)sibling;
}
/**
* Returns the next sibling element of the specified node and checks that
* the local name is equal to {@code localName}.
*
* @param node the node
* @return the next sibling element of the specified node
* @throws NullPointerException if {@code node == null}
* @throws MarshalException if no such element or the local name is not
* equal to {@code localName}
*/
@Deprecated
public static Element getNextSiblingElement(Node node, String localName)
throws MarshalException
{
return verifyElement(getNextSiblingElement(node), localName);
}
/**
* Returns the next sibling element of the specified node and checks that
* the local name is equal to {@code localName} and the namespace is equal to
* {@code namespaceURI}
*
* @param node the node
* @return the next sibling element of the specified node
* @throws NullPointerException if {@code node == null}
* @throws MarshalException if no such element or the local name is not
* equal to {@code localName}
*/
public static Element getNextSiblingElement(Node node, String localName, String namespaceURI)
throws MarshalException
{
return verifyElement(getNextSiblingElement(node), localName, namespaceURI);
}
/**
* Returns the attribute value for the attribute with the specified name.
* Returns null if there is no such attribute, or
* the empty string if the attribute value is empty.
*
* <p>This works around a limitation of the DOM
* {@code Element.getAttributeNode} method, which does not distinguish
* between an unspecified attribute and an attribute with a value of
* "" (it returns "" for both cases).
*
* @param elem the element containing the attribute
* @param name the name of the attribute
* @return the attribute value (may be null if unspecified)
*/
public static String getAttributeValue(Element elem, String name) {
Attr attr = elem.getAttributeNodeNS(null, name);
return (attr == null) ? null : attr.getValue();
}
/**
* Returns the attribute value for the attribute with the specified name.
* Returns null if there is no such attribute, or
* the empty string if the attribute value is empty.
*
* <p>This works around a limitation of the DOM
* {@code Element.getAttributeNode} method, which does not distinguish
* between an unspecified attribute and an attribute with a value of
* "" (it returns "" for both cases).
*
* @param elem the element containing the attribute
* @param name the name of the attribute
* @return the attribute value (may be null if unspecified)
*/
public static <N> String getIdAttributeValue(Element elem, String name) {
Attr attr = elem.getAttributeNodeNS(null, name);
if (attr != null && !attr.isId()) {
elem.setIdAttributeNode(attr, true);
}
return (attr == null) ? null : attr.getValue();
}
/**
* Returns a Set of {@code Node}s, backed by the specified
* {@code NodeList}.
*
* @param nl the NodeList
* @return a Set of Nodes
*/
public static Set<Node> nodeSet(NodeList nl) {
return new NodeSet(nl);
}
static class NodeSet extends AbstractSet<Node> {
private NodeList nl;
public NodeSet(NodeList nl) {
this.nl = nl;
}
public int size() { return nl.getLength(); }
public Iterator<Node> iterator() {
return new Iterator<Node>() {
private int index;
public void remove() {
throw new UnsupportedOperationException();
}
public Node next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return nl.item(index++);
}
public boolean hasNext() {
return index < nl.getLength();
}
};
}
}
/**
* Returns the prefix associated with the specified namespace URI
*
* @param context contains the namespace map
* @param nsURI the namespace URI
* @return the prefix associated with the specified namespace URI, or
* null if not set
*/
public static String getNSPrefix(XMLCryptoContext context, String nsURI) {
if (context != null) {
return context.getNamespacePrefix
(nsURI, context.getDefaultNamespacePrefix());
} else {
return null;
}
}
/**
* Returns the prefix associated with the XML Signature namespace URI
*
* @param context contains the namespace map
* @return the prefix associated with the specified namespace URI, or
* null if not set
*/
public static String getSignaturePrefix(XMLCryptoContext context) {
return getNSPrefix(context, XMLSignature.XMLNS);
}
/**
* Removes all children nodes from the specified node.
*
* @param node the parent node whose children are to be removed
*/
public static void removeAllChildren(Node node) {
Node firstChild = node.getFirstChild();
while (firstChild != null) {
Node nodeToRemove = firstChild;
firstChild = firstChild.getNextSibling();
node.removeChild(nodeToRemove);
}
}
/**
* Compares 2 nodes for equality. Implementation is not complete.
*/
public static boolean nodesEqual(Node thisNode, Node otherNode) {
if (thisNode == otherNode) {
return true;
}
if (thisNode.getNodeType() != otherNode.getNodeType()) {
return false;
}
// FIXME - test content, etc
return true;
}
/**
* Checks if child element has same owner document before
* appending to the parent, and imports it to the parent's document
* if necessary.
*/
public static void appendChild(Node parent, Node child) {
Document ownerDoc = getOwnerDocument(parent);
if (child.getOwnerDocument() != ownerDoc) {
parent.appendChild(ownerDoc.importNode(child, true));
} else {
parent.appendChild(child);
}
}
public static boolean paramsEqual(AlgorithmParameterSpec spec1,
AlgorithmParameterSpec spec2) {
if (spec1 == spec2) {
return true;
}
if (spec1 instanceof XPathFilter2ParameterSpec &&
spec2 instanceof XPathFilter2ParameterSpec) {
return paramsEqual((XPathFilter2ParameterSpec)spec1,
(XPathFilter2ParameterSpec)spec2);
}
if (spec1 instanceof ExcC14NParameterSpec &&
spec2 instanceof ExcC14NParameterSpec) {
return paramsEqual((ExcC14NParameterSpec) spec1,
(ExcC14NParameterSpec)spec2);
}
if (spec1 instanceof XPathFilterParameterSpec &&
spec2 instanceof XPathFilterParameterSpec) {
return paramsEqual((XPathFilterParameterSpec)spec1,
(XPathFilterParameterSpec)spec2);
}
if (spec1 instanceof XSLTTransformParameterSpec &&
spec2 instanceof XSLTTransformParameterSpec) {
return paramsEqual((XSLTTransformParameterSpec)spec1,
(XSLTTransformParameterSpec)spec2);
}
return false;
}
private static boolean paramsEqual(XPathFilter2ParameterSpec spec1,
XPathFilter2ParameterSpec spec2)
{
@SuppressWarnings("unchecked")
List<XPathType> types = spec1.getXPathList();
@SuppressWarnings("unchecked")
List<XPathType> otypes = spec2.getXPathList();
int size = types.size();
if (size != otypes.size()) {
return false;
}
for (int i = 0; i < size; i++) {
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()) {
return false;
}
}
return true;
}
private static boolean paramsEqual(ExcC14NParameterSpec spec1,
ExcC14NParameterSpec spec2)
{
return spec1.getPrefixList().equals(spec2.getPrefixList());
}
private static boolean paramsEqual(XPathFilterParameterSpec spec1,
XPathFilterParameterSpec spec2)
{
return spec1.getXPath().equals(spec2.getXPath()) &&
spec1.getNamespaceMap().equals(spec2.getNamespaceMap());
}
private static boolean paramsEqual(XSLTTransformParameterSpec spec1,
XSLTTransformParameterSpec spec2)
{
XMLStructure ostylesheet = spec2.getStylesheet();
if (!(ostylesheet instanceof javax.xml.crypto.dom.DOMStructure)) {
return false;
}
Node ostylesheetElem =
((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode();
XMLStructure stylesheet = spec1.getStylesheet();
Node stylesheetElem =
((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode();
return nodesEqual(stylesheetElem, ostylesheetElem);
}
public static boolean isNamespace(Node node)
{
final short nodeType = node.getNodeType();
if (nodeType == Node.ATTRIBUTE_NODE) {
final String namespaceURI = node.getNamespaceURI();
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI);
}
return false;
}
}

View File

@@ -0,0 +1,295 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMX509Data.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.*;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
/**
* DOM-based implementation of X509Data.
*
*/
//@@@ check for illegal combinations of data violating MUSTs in W3c spec
public final class DOMX509Data extends DOMStructure implements X509Data {
private final List<Object> content;
private CertificateFactory cf;
/**
* Creates a DOMX509Data.
*
* @param content a list of one or more X.509 data types. Valid types are
* {@link String} (subject names), {@code byte[]} (subject key ids),
* {@link java.security.cert.X509Certificate}, {@link X509CRL},
* or {@link javax.xml.dsig.XMLStructure}
* objects or elements from an external namespace). The list is
* defensively copied to protect against subsequent modification.
* @throws NullPointerException if {@code content} is {@code null}
* @throws IllegalArgumentException if {@code content} is empty
* @throws ClassCastException if {@code content} contains any entries
* that are not of one of the valid types mentioned above
*/
public DOMX509Data(List<?> content) {
if (content == null) {
throw new NullPointerException("content cannot be null");
}
List<Object> contentCopy = new ArrayList<>(content);
if (contentCopy.isEmpty()) {
throw new IllegalArgumentException("content cannot be empty");
}
for (int i = 0, size = contentCopy.size(); i < size; i++) {
Object x509Type = contentCopy.get(i);
if (x509Type instanceof String) {
new X500Principal((String)x509Type);
} else if (!(x509Type instanceof byte[]) &&
!(x509Type instanceof X509Certificate) &&
!(x509Type instanceof X509CRL) &&
!(x509Type instanceof XMLStructure)) {
throw new ClassCastException
("content["+i+"] is not a valid X509Data type");
}
}
this.content = Collections.unmodifiableList(contentCopy);
}
/**
* Creates a {@code DOMX509Data} from an element.
*
* @param xdElem an X509Data element
* @throws MarshalException if there is an error while unmarshalling
*/
public DOMX509Data(Element xdElem) throws MarshalException {
// get all children nodes
List<Object> newContent = new ArrayList<>();
Node firstChild = xdElem.getFirstChild();
while (firstChild != null) {
if (firstChild.getNodeType() == Node.ELEMENT_NODE) {
Element childElem = (Element)firstChild;
String localName = childElem.getLocalName();
String namespace = childElem.getNamespaceURI();
if ("X509Certificate".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(unmarshalX509Certificate(childElem));
} else if ("X509IssuerSerial".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(new DOMX509IssuerSerial(childElem));
} else if ("X509SubjectName".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(childElem.getFirstChild().getNodeValue());
} else if ("X509SKI".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
String content = XMLUtils.getFullTextChildrenFromNode(childElem);
newContent.add(XMLUtils.decode(content));
} else if ("X509CRL".equals(localName) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(unmarshalX509CRL(childElem));
} else {
newContent.add(new javax.xml.crypto.dom.DOMStructure(childElem));
}
}
firstChild = firstChild.getNextSibling();
}
this.content = Collections.unmodifiableList(newContent);
}
public List<Object> getContent() {
return content;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element xdElem = DOMUtils.createElement(ownerDoc, "X509Data",
XMLSignature.XMLNS, dsPrefix);
// append children and preserve order
for (int i = 0, size = content.size(); i < size; i++) {
Object object = content.get(i);
if (object instanceof X509Certificate) {
marshalCert((X509Certificate)object,xdElem,ownerDoc,dsPrefix);
} else if (object instanceof XMLStructure) {
if (object instanceof X509IssuerSerial) {
((DOMX509IssuerSerial)object).marshal
(xdElem, dsPrefix, context);
} else {
javax.xml.crypto.dom.DOMStructure domContent =
(javax.xml.crypto.dom.DOMStructure)object;
DOMUtils.appendChild(xdElem, domContent.getNode());
}
} else if (object instanceof byte[]) {
marshalSKI((byte[])object, xdElem, ownerDoc, dsPrefix);
} else if (object instanceof String) {
marshalSubjectName((String)object, xdElem, ownerDoc,dsPrefix);
} else if (object instanceof X509CRL) {
marshalCRL((X509CRL)object, xdElem, ownerDoc, dsPrefix);
}
}
parent.appendChild(xdElem);
}
private void marshalSKI(byte[] skid, Node parent, Document doc,
String dsPrefix)
{
Element skidElem = DOMUtils.createElement(doc, "X509SKI",
XMLSignature.XMLNS, dsPrefix);
skidElem.appendChild(doc.createTextNode(XMLUtils.encodeToString(skid)));
parent.appendChild(skidElem);
}
private void marshalSubjectName(String name, Node parent, Document doc,
String dsPrefix)
{
Element snElem = DOMUtils.createElement(doc, "X509SubjectName",
XMLSignature.XMLNS, dsPrefix);
snElem.appendChild(doc.createTextNode(name));
parent.appendChild(snElem);
}
private void marshalCert(X509Certificate cert, Node parent, Document doc,
String dsPrefix)
throws MarshalException
{
Element certElem = DOMUtils.createElement(doc, "X509Certificate",
XMLSignature.XMLNS, dsPrefix);
try {
certElem.appendChild(doc.createTextNode
(XMLUtils.encodeToString(cert.getEncoded())));
} catch (CertificateEncodingException e) {
throw new MarshalException("Error encoding X509Certificate", e);
}
parent.appendChild(certElem);
}
private void marshalCRL(X509CRL crl, Node parent, Document doc,
String dsPrefix)
throws MarshalException
{
Element crlElem = DOMUtils.createElement(doc, "X509CRL",
XMLSignature.XMLNS, dsPrefix);
try {
crlElem.appendChild(doc.createTextNode
(XMLUtils.encodeToString(crl.getEncoded())));
} catch (CRLException e) {
throw new MarshalException("Error encoding X509CRL", e);
}
parent.appendChild(crlElem);
}
private X509Certificate unmarshalX509Certificate(Element elem)
throws MarshalException
{
try (ByteArrayInputStream bs = unmarshalBase64Binary(elem)) {
return (X509Certificate)cf.generateCertificate(bs);
} catch (CertificateException e) {
throw new MarshalException("Cannot create X509Certificate", e);
} catch (IOException e) {
throw new MarshalException("Error closing stream", e);
}
}
private X509CRL unmarshalX509CRL(Element elem) throws MarshalException {
try (ByteArrayInputStream bs = unmarshalBase64Binary(elem)) {
return (X509CRL)cf.generateCRL(bs);
} catch (CRLException e) {
throw new MarshalException("Cannot create X509CRL", e);
} catch (IOException e) {
throw new MarshalException("Error closing stream", e);
}
}
private ByteArrayInputStream unmarshalBase64Binary(Element elem)
throws MarshalException {
try {
if (cf == null) {
cf = CertificateFactory.getInstance("X.509");
}
String content = XMLUtils.getFullTextChildrenFromNode(elem);
return new ByteArrayInputStream(XMLUtils.decode(content));
} catch (CertificateException e) {
throw new MarshalException("Cannot create CertificateFactory", e);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof X509Data)) {
return false;
}
X509Data oxd = (X509Data)o;
@SuppressWarnings("unchecked") List<Object> ocontent = oxd.getContent();
int size = content.size();
if (size != ocontent.size()) {
return false;
}
for (int i = 0; i < size; i++) {
Object x = content.get(i);
Object ox = ocontent.get(i);
if (x instanceof byte[]) {
if (!(ox instanceof byte[]) ||
!Arrays.equals((byte[])x, (byte[])ox)) {
return false;
}
} else {
if (!(x.equals(ox))) {
return false;
}
}
}
return true;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + content.hashCode();
return result;
}
}

View File

@@ -0,0 +1,142 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMX509IssuerSerial.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial;
import java.math.BigInteger;
import javax.security.auth.x500.X500Principal;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of X509IssuerSerial.
*
*/
public final class DOMX509IssuerSerial extends DOMStructure
implements X509IssuerSerial {
private final String issuerName;
private final BigInteger serialNumber;
/**
* Creates a {@code DOMX509IssuerSerial} containing the specified
* issuer distinguished name/serial number pair.
*
* @param issuerName the X.509 issuer distinguished name in RFC 2253
* String format
* @param serialNumber the serial number
* @throws IllegalArgumentException if the format of {@code issuerName}
* is not RFC 2253 compliant
* @throws NullPointerException if {@code issuerName} or
* {@code serialNumber} is {@code null}
*/
public DOMX509IssuerSerial(String issuerName, BigInteger serialNumber) {
if (issuerName == null) {
throw new NullPointerException("issuerName cannot be null");
}
if (serialNumber == null) {
throw new NullPointerException("serialNumber cannot be null");
}
// check that issuer distinguished name conforms to RFC 2253
new X500Principal(issuerName);
this.issuerName = issuerName;
this.serialNumber = serialNumber;
}
/**
* Creates a {@code DOMX509IssuerSerial} from an element.
*
* @param isElem an X509IssuerSerial element
*/
public DOMX509IssuerSerial(Element isElem) throws MarshalException {
Element iNElem = DOMUtils.getFirstChildElement(isElem,
"X509IssuerName",
XMLSignature.XMLNS);
Element sNElem = DOMUtils.getNextSiblingElement(iNElem,
"X509SerialNumber",
XMLSignature.XMLNS);
issuerName = iNElem.getFirstChild().getNodeValue();
serialNumber = new BigInteger(sNElem.getFirstChild().getNodeValue());
}
public String getIssuerName() {
return issuerName;
}
public BigInteger getSerialNumber() {
return serialNumber;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element isElem = DOMUtils.createElement(ownerDoc, "X509IssuerSerial",
XMLSignature.XMLNS, dsPrefix);
Element inElem = DOMUtils.createElement(ownerDoc, "X509IssuerName",
XMLSignature.XMLNS, dsPrefix);
Element snElem = DOMUtils.createElement(ownerDoc, "X509SerialNumber",
XMLSignature.XMLNS, dsPrefix);
inElem.appendChild(ownerDoc.createTextNode(issuerName));
snElem.appendChild(ownerDoc.createTextNode(serialNumber.toString()));
isElem.appendChild(inElem);
isElem.appendChild(snElem);
parent.appendChild(isElem);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof X509IssuerSerial)) {
return false;
}
X509IssuerSerial ois = (X509IssuerSerial)obj;
return issuerName.equals(ois.getIssuerName()) &&
serialNumber.equals(ois.getSerialNumber());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + issuerName.hashCode();
result = 31 * result + serialNumber.hashCode();
return result;
}
}

View File

@@ -0,0 +1,264 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMXMLObject.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import java.security.Provider;
import java.util.*;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* DOM-based implementation of XMLObject.
*
*/
public final class DOMXMLObject extends DOMStructure implements XMLObject {
private final String id;
private final String mimeType;
private final String encoding;
private final List<XMLStructure> content;
private Element objectElem;
/**
* Creates an {@code XMLObject} from the specified parameters.
*
* @param content a list of {@link XMLStructure}s. The list
* is defensively copied to protect against subsequent modification.
* May be {@code null} or empty.
* @param id the Id (may be {@code null})
* @param mimeType the mime type (may be {@code null})
* @param encoding the encoding (may be {@code null})
* @throws ClassCastException if {@code content} contains any
* entries that are not of type {@link XMLStructure}
*/
public DOMXMLObject(List<? extends XMLStructure> content, String id,
String mimeType, String encoding)
{
if (content == null || content.isEmpty()) {
this.content = Collections.emptyList();
} else {
this.content = Collections.unmodifiableList(
new ArrayList<>(content));
for (int i = 0, size = this.content.size(); i < size; i++) {
if (!(this.content.get(i) instanceof XMLStructure)) {
throw new ClassCastException
("content["+i+"] is not a valid type");
}
}
}
this.id = id;
this.mimeType = mimeType;
this.encoding = encoding;
}
/**
* Creates an {@code XMLObject} from an element.
*
* @param objElem an Object element
* @throws MarshalException if there is an error when unmarshalling
*/
public DOMXMLObject(Element objElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
// unmarshal attributes
this.encoding = DOMUtils.getAttributeValue(objElem, "Encoding");
Attr attr = objElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
this.id = attr.getValue();
objElem.setIdAttributeNode(attr, true);
} else {
this.id = null;
}
this.mimeType = DOMUtils.getAttributeValue(objElem, "MimeType");
List<XMLStructure> newContent = new ArrayList<>();
Node firstChild = objElem.getFirstChild();
while (firstChild != null) {
if (firstChild.getNodeType() == Node.ELEMENT_NODE) {
Element childElem = (Element)firstChild;
String tag = childElem.getLocalName();
String namespace = childElem.getNamespaceURI();
if ("Manifest".equals(tag) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(new DOMManifest(childElem, context, provider));
} else if ("SignatureProperties".equals(tag) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(new DOMSignatureProperties(childElem));
} else if ("X509Data".equals(tag) && XMLSignature.XMLNS.equals(namespace)) {
newContent.add(new DOMX509Data(childElem));
} else {
//@@@FIXME: check for other dsig structures
newContent.add(new javax.xml.crypto.dom.DOMStructure(firstChild));
}
} else {
newContent.add(new javax.xml.crypto.dom.DOMStructure(firstChild));
}
firstChild = firstChild.getNextSibling();
}
// Here we capture namespace declarations, so that when they're marshalled back
// out, we can make copies of them. Note that attributes are NOT captured.
NamedNodeMap nnm = objElem.getAttributes();
for (int idx = 0 ; idx < nnm.getLength() ; idx++) {
Node nsDecl = nnm.item(idx);
if (DOMUtils.isNamespace(nsDecl)) {
newContent.add(new javax.xml.crypto.dom.DOMStructure(nsDecl));
}
}
if (newContent.isEmpty()) {
this.content = Collections.emptyList();
} else {
this.content = Collections.unmodifiableList(newContent);
}
this.objectElem = objElem;
}
public List<XMLStructure> getContent() {
return content;
}
public String getId() {
return id;
}
public String getMimeType() {
return mimeType;
}
public String getEncoding() {
return encoding;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException {
Document ownerDoc = DOMUtils.getOwnerDocument(parent);
Element objElem = objectElem != null ? objectElem : null;
if (objElem == null) {
objElem = DOMUtils.createElement(ownerDoc, "Object",
XMLSignature.XMLNS, dsPrefix);
// set attributes
DOMUtils.setAttributeID(objElem, "Id", id);
DOMUtils.setAttribute(objElem, "MimeType", mimeType);
DOMUtils.setAttribute(objElem, "Encoding", encoding);
// create and append any elements and mixed content, if necessary
for (XMLStructure object : content) {
if (object instanceof DOMStructure) {
((DOMStructure)object).marshal(objElem, dsPrefix, context);
} else {
javax.xml.crypto.dom.DOMStructure domObject =
(javax.xml.crypto.dom.DOMStructure)object;
DOMUtils.appendChild(objElem, domObject.getNode());
}
}
}
parent.appendChild(objElem);
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof XMLObject)) {
return false;
}
XMLObject oxo = (XMLObject)o;
boolean idsEqual = id == null ? oxo.getId() == null
: id.equals(oxo.getId());
boolean encodingsEqual =
encoding == null ? oxo.getEncoding() == null
: encoding.equals(oxo.getEncoding());
boolean mimeTypesEqual =
mimeType == null ? oxo.getMimeType() == null
: mimeType.equals(oxo.getMimeType());
return idsEqual && encodingsEqual && mimeTypesEqual &&
equalsContent(oxo.getContent());
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
if (encoding != null) {
result = 31 * result + encoding.hashCode();
}
if (mimeType != null) {
result = 31 * result + mimeType.hashCode();
}
result = 31 * result + content.hashCode();
return result;
}
private boolean equalsContent(List<XMLStructure> otherContent) {
if (content.size() != otherContent.size()) {
return false;
}
for (int i = 0, osize = otherContent.size(); i < osize; i++) {
XMLStructure oxs = otherContent.get(i);
XMLStructure xs = content.get(i);
if (oxs instanceof javax.xml.crypto.dom.DOMStructure) {
if (!(xs instanceof javax.xml.crypto.dom.DOMStructure)) {
return false;
}
Node onode = ((javax.xml.crypto.dom.DOMStructure)oxs).getNode();
Node node = ((javax.xml.crypto.dom.DOMStructure)xs).getNode();
if (!DOMUtils.nodesEqual(node, onode)) {
return false;
}
} else {
if (!(xs.equals(oxs))) {
return false;
}
}
}
return true;
}
}

View File

@@ -0,0 +1,634 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Portions copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* ===========================================================================
*
* (C) Copyright IBM Corp. 2003 All Rights Reserved.
*
* ===========================================================================
*/
/*
* $Id: DOMXMLSignature.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.Provider;
import java.util.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
/**
* DOM-based implementation of XMLSignature.
*
*/
public final class DOMXMLSignature extends DOMStructure
implements XMLSignature {
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMXMLSignature.class);
private String id;
private SignatureValue sv;
private KeyInfo ki;
private List<XMLObject> objects;
private SignedInfo si;
private Document ownerDoc = null;
private Element localSigElem = null;
private Element sigElem = null;
private boolean validationStatus;
private boolean validated = false;
private KeySelectorResult ksr;
private Map<String, XMLStructure> signatureIdMap;
static {
com.sun.org.apache.xml.internal.security.Init.init();
}
/**
* Creates a {@code DOMXMLSignature} from the specified components.
*
* @param si the {@code SignedInfo}
* @param ki the {@code KeyInfo}, or {@code null} if not specified
* @param objs a list of {@code XMLObject}s or {@code null}
* if not specified. The list is copied to protect against subsequent
* modification.
* @param id an optional id (specify {@code null} to omit)
* @param signatureValueId an optional id (specify {@code null} to
* omit)
* @throws NullPointerException if {@code si} is {@code null}
*/
public DOMXMLSignature(SignedInfo si, KeyInfo ki,
List<? extends XMLObject> objs,
String id, String signatureValueId)
{
if (si == null) {
throw new NullPointerException("signedInfo cannot be null");
}
this.si = si;
this.id = id;
this.sv = new DOMSignatureValue(signatureValueId);
if (objs == null) {
this.objects = Collections.emptyList();
} else {
this.objects =
Collections.unmodifiableList(new ArrayList<>(objs));
for (int i = 0, size = this.objects.size(); i < size; i++) {
if (!(this.objects.get(i) instanceof XMLObject)) {
throw new ClassCastException
("objs["+i+"] is not an XMLObject");
}
}
}
this.ki = ki;
}
/**
* Creates a {@code DOMXMLSignature} from XML.
*
* @param sigElem Signature element
* @throws MarshalException if XMLSignature cannot be unmarshalled
*/
public DOMXMLSignature(Element sigElem, XMLCryptoContext context,
Provider provider)
throws MarshalException
{
localSigElem = sigElem;
ownerDoc = localSigElem.getOwnerDocument();
// get Id attribute, if specified
id = DOMUtils.getAttributeValue(localSigElem, "Id");
// unmarshal SignedInfo
Element siElem = DOMUtils.getFirstChildElement(localSigElem,
"SignedInfo",
XMLSignature.XMLNS);
si = new DOMSignedInfo(siElem, context, provider);
// unmarshal SignatureValue
Element sigValElem = DOMUtils.getNextSiblingElement(siElem,
"SignatureValue",
XMLSignature.XMLNS);
sv = new DOMSignatureValue(sigValElem);
// unmarshal KeyInfo, if specified
Element nextSibling = DOMUtils.getNextSiblingElement(sigValElem);
if (nextSibling != null && nextSibling.getLocalName().equals("KeyInfo")
&& XMLSignature.XMLNS.equals(nextSibling.getNamespaceURI())) {
ki = new DOMKeyInfo(nextSibling, context, provider);
nextSibling = DOMUtils.getNextSiblingElement(nextSibling);
}
// unmarshal Objects, if specified
if (nextSibling == null) {
objects = Collections.emptyList();
} else {
List<XMLObject> tempObjects = new ArrayList<>();
while (nextSibling != null) {
String name = nextSibling.getLocalName();
String namespace = nextSibling.getNamespaceURI();
if (!"Object".equals(name) || !XMLSignature.XMLNS.equals(namespace)) {
throw new MarshalException("Invalid element name: " + namespace + ":" + name +
", expected KeyInfo or Object");
}
tempObjects.add(new DOMXMLObject(nextSibling,
context, provider));
nextSibling = DOMUtils.getNextSiblingElement(nextSibling);
}
objects = Collections.unmodifiableList(tempObjects);
}
}
public String getId() {
return id;
}
public KeyInfo getKeyInfo() {
return ki;
}
public SignedInfo getSignedInfo() {
return si;
}
public List<XMLObject> getObjects() {
return objects;
}
public SignatureValue getSignatureValue() {
return sv;
}
public KeySelectorResult getKeySelectorResult() {
return ksr;
}
@Override
public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
throws MarshalException
{
marshal(parent, null, dsPrefix, context);
}
public void marshal(Node parent, Node nextSibling, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
ownerDoc = DOMUtils.getOwnerDocument(parent);
sigElem = DOMUtils.createElement(ownerDoc, "Signature",
XMLSignature.XMLNS, dsPrefix);
// append xmlns attribute
if (dsPrefix == null || dsPrefix.length() == 0) {
sigElem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns",
XMLSignature.XMLNS);
} else {
sigElem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" +
dsPrefix, XMLSignature.XMLNS);
}
// create and append SignedInfo element
((DOMSignedInfo)si).marshal(sigElem, dsPrefix, context);
// create and append SignatureValue element
((DOMSignatureValue)sv).marshal(sigElem, dsPrefix, context);
// create and append KeyInfo element if necessary
if (ki != null) {
((DOMKeyInfo)ki).marshal(sigElem, null, dsPrefix, context);
}
// create and append Object elements if necessary
for (int i = 0, size = objects.size(); i < size; i++) {
((DOMXMLObject)objects.get(i)).marshal(sigElem, dsPrefix, context);
}
// append Id attribute
DOMUtils.setAttributeID(sigElem, "Id", id);
parent.insertBefore(sigElem, nextSibling);
}
@Override
public boolean validate(XMLValidateContext vc)
throws XMLSignatureException
{
if (vc == null) {
throw new NullPointerException("validateContext is null");
}
if (!(vc instanceof DOMValidateContext)) {
throw new ClassCastException
("validateContext must be of type DOMValidateContext");
}
if (validated) {
return validationStatus;
}
// validate the signature
boolean sigValidity = sv.validate(vc);
if (!sigValidity) {
validationStatus = false;
validated = true;
return validationStatus;
}
// validate all References
@SuppressWarnings("unchecked")
List<Reference> refs = this.si.getReferences();
boolean validateRefs = true;
for (int i = 0, size = refs.size(); validateRefs && i < size; i++) {
Reference ref = refs.get(i);
boolean refValid = ref.validate(vc);
LOG.debug("Reference [{}] is valid: {}", ref.getURI(), refValid);
validateRefs &= refValid;
}
if (!validateRefs) {
LOG.debug("Couldn't validate the References");
validationStatus = false;
validated = true;
return validationStatus;
}
// validate Manifests, if property set
boolean validateMans = true;
if (Boolean.TRUE.equals(vc.getProperty
("org.jcp.xml.dsig.validateManifests")))
{
for (int i=0, size=objects.size(); validateMans && i < size; i++) {
XMLObject xo = objects.get(i);
@SuppressWarnings("unchecked")
List<XMLStructure> content = xo.getContent();
int csize = content.size();
for (int j = 0; validateMans && j < csize; j++) {
XMLStructure xs = content.get(j);
if (xs instanceof Manifest) {
LOG.debug("validating manifest");
Manifest man = (Manifest)xs;
@SuppressWarnings("unchecked")
List<Reference> manRefs = man.getReferences();
int rsize = manRefs.size();
for (int k = 0; validateMans && k < rsize; k++) {
Reference ref = manRefs.get(k);
boolean refValid = ref.validate(vc);
LOG.debug(
"Manifest ref [{}] is valid: {}", ref.getURI(), refValid
);
validateMans &= refValid;
}
}
}
}
}
validationStatus = validateMans;
validated = true;
return validationStatus;
}
@Override
public void sign(XMLSignContext signContext)
throws MarshalException, XMLSignatureException
{
if (signContext == null) {
throw new NullPointerException("signContext cannot be null");
}
DOMSignContext context = (DOMSignContext)signContext;
marshal(context.getParent(), context.getNextSibling(),
DOMUtils.getSignaturePrefix(context), context);
// generate references and signature value
List<Reference> allReferences = new ArrayList<>();
// traverse the Signature and register all objects with IDs that
// may contain References
signatureIdMap = new HashMap<>();
signatureIdMap.put(id, this);
signatureIdMap.put(si.getId(), si);
@SuppressWarnings("unchecked")
List<Reference> refs = si.getReferences();
for (Reference ref : refs) {
signatureIdMap.put(ref.getId(), ref);
}
for (XMLObject obj : objects) {
signatureIdMap.put(obj.getId(), obj);
@SuppressWarnings("unchecked")
List<XMLStructure> content = obj.getContent();
for (XMLStructure xs : content) {
if (xs instanceof Manifest) {
Manifest man = (Manifest)xs;
signatureIdMap.put(man.getId(), man);
@SuppressWarnings("unchecked")
List<Reference> manRefs = man.getReferences();
for (Reference ref : manRefs) {
allReferences.add(ref);
signatureIdMap.put(ref.getId(), ref);
}
}
}
}
// always add SignedInfo references after Manifest references so
// that Manifest reference are digested first
allReferences.addAll(refs);
// generate/digest each reference
for (Reference ref : allReferences) {
digestReference((DOMReference)ref, signContext);
}
// do final sweep to digest any references that were skipped or missed
for (Reference ref : allReferences) {
if (((DOMReference)ref).isDigested()) {
continue;
}
((DOMReference)ref).digest(signContext);
}
Key signingKey = null;
try {
KeySelectorResult keySelectorResult = signContext.getKeySelector().select(ki,
KeySelector.Purpose.SIGN,
si.getSignatureMethod(),
signContext);
signingKey = keySelectorResult.getKey();
if (signingKey == null) {
throw new XMLSignatureException("the keySelector did not " +
"find a signing key");
}
ksr = keySelectorResult;
} catch (KeySelectorException kse) {
throw new XMLSignatureException("cannot find signing key", kse);
}
// calculate signature value
try {
byte[] val = ((AbstractDOMSignatureMethod)
si.getSignatureMethod()).sign(signingKey, si, signContext);
((DOMSignatureValue)sv).setValue(val);
} catch (InvalidKeyException ike) {
throw new XMLSignatureException(ike);
}
this.localSigElem = sigElem;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof XMLSignature)) {
return false;
}
XMLSignature osig = (XMLSignature)o;
boolean idEqual =
id == null ? osig.getId() == null : id.equals(osig.getId());
boolean keyInfoEqual =
ki == null ? osig.getKeyInfo() == null
: ki.equals(osig.getKeyInfo());
return idEqual && keyInfoEqual &&
sv.equals(osig.getSignatureValue()) &&
si.equals(osig.getSignedInfo()) &&
objects.equals(osig.getObjects());
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
if (ki != null) {
result = 31 * result + ki.hashCode();
}
result = 31 * result + sv.hashCode();
result = 31 * result + si.hashCode();
result = 31 * result + objects.hashCode();
return result;
}
private void digestReference(DOMReference ref, XMLSignContext signContext)
throws XMLSignatureException
{
if (ref.isDigested()) {
return;
}
// check dependencies
String uri = ref.getURI();
if (Utils.sameDocumentURI(uri)) {
String parsedId = Utils.parseIdFromSameDocumentURI(uri);
if (parsedId != null && signatureIdMap.containsKey(parsedId)) {
XMLStructure xs = signatureIdMap.get(parsedId);
if (xs instanceof DOMReference) {
digestReference((DOMReference)xs, signContext);
} else if (xs instanceof Manifest) {
Manifest man = (Manifest)xs;
List<Reference> manRefs = DOMManifest.getManifestReferences(man);
for (int i = 0, size = manRefs.size(); i < size; i++) {
digestReference((DOMReference)manRefs.get(i),
signContext);
}
}
}
// if uri="" and there are XPath Transforms, there may be
// reference dependencies in the XPath Transform - so be on
// the safe side, and skip and do at end in the final sweep
if (uri.length() == 0) {
@SuppressWarnings("unchecked")
List<Transform> transforms = ref.getTransforms();
for (Transform transform : transforms) {
String transformAlg = transform.getAlgorithm();
if (transformAlg.equals(Transform.XPATH) ||
transformAlg.equals(Transform.XPATH2)) {
return;
}
}
}
}
ref.digest(signContext);
}
public class DOMSignatureValue extends DOMStructure
implements SignatureValue
{
private String id;
private byte[] value;
private String valueBase64;
private Element sigValueElem;
private boolean validated = false;
private boolean validationStatus;
DOMSignatureValue(String id) {
this.id = id;
}
DOMSignatureValue(Element sigValueElem)
throws MarshalException
{
// base64 decode signatureValue
String content = XMLUtils.getFullTextChildrenFromNode(sigValueElem);
value = XMLUtils.decode(content);
Attr attr = sigValueElem.getAttributeNodeNS(null, "Id");
if (attr != null) {
id = attr.getValue();
sigValueElem.setIdAttributeNode(attr, true);
} else {
id = null;
}
this.sigValueElem = sigValueElem;
}
public String getId() {
return id;
}
public byte[] getValue() {
return (value == null) ? null : (byte[])value.clone();
}
public String getEncodedValue() {
return valueBase64;
}
@Override
public boolean validate(XMLValidateContext validateContext)
throws XMLSignatureException
{
if (validateContext == null) {
throw new NullPointerException("context cannot be null");
}
if (validated) {
return validationStatus;
}
// get validating key
SignatureMethod sm = si.getSignatureMethod();
Key validationKey = null;
KeySelectorResult ksResult = null;
try {
KeySelector keySelector = validateContext.getKeySelector();
if (keySelector != null) {
ksResult = keySelector.select
(ki, KeySelector.Purpose.VERIFY, sm, validateContext);
if (ksResult != null) {
validationKey = ksResult.getKey();
}
}
if (validationKey == null) {
throw new XMLSignatureException("the keyselector did not " +
"find a validation key");
}
} catch (KeySelectorException kse) {
throw new XMLSignatureException("cannot find validation " +
"key", kse);
}
// canonicalize SignedInfo and verify signature
try {
validationStatus = ((AbstractDOMSignatureMethod)sm).verify
(validationKey, si, value, validateContext);
} catch (Exception e) {
throw new XMLSignatureException(e);
}
validated = true;
ksr = ksResult;
return validationStatus;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SignatureValue)) {
return false;
}
SignatureValue osv = (SignatureValue)o;
boolean idEqual =
id == null ? osv.getId() == null : id.equals(osv.getId());
//XXX compare signature values?
return idEqual;
}
@Override
public int hashCode() {
int result = 17;
if (id != null) {
result = 31 * result + id.hashCode();
}
return result;
}
public void marshal(Node parent, String dsPrefix,
DOMCryptoContext context)
throws MarshalException
{
// create SignatureValue element
sigValueElem = DOMUtils.createElement(ownerDoc, "SignatureValue",
XMLSignature.XMLNS, dsPrefix);
if (valueBase64 != null) {
sigValueElem.appendChild(ownerDoc.createTextNode(valueBase64));
}
// append Id attribute, if specified
DOMUtils.setAttributeID(sigValueElem, "Id", id);
parent.appendChild(sigValueElem);
}
void setValue(byte[] value) {
this.value = value;
valueBase64 = XMLUtils.encodeToString(value);
sigValueElem.appendChild(ownerDoc.createTextNode(valueBase64));
}
}
}

View File

@@ -0,0 +1,385 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMXMLSignatureFactory.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dom.DOMCryptoContext;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* DOM-based implementation of XMLSignatureFactory.
*
*/
public final class DOMXMLSignatureFactory extends XMLSignatureFactory {
/**
* Initializes a new instance of this class.
*/
public DOMXMLSignatureFactory() {}
public XMLSignature newXMLSignature(SignedInfo si, KeyInfo ki) {
return new DOMXMLSignature(si, ki, null, null, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public XMLSignature newXMLSignature(SignedInfo si, KeyInfo ki,
List objects, String id, String signatureValueId) {
return new DOMXMLSignature(si, ki, objects, id, signatureValueId);
}
public Reference newReference(String uri, DigestMethod dm) {
return newReference(uri, dm, null, null, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Reference newReference(String uri, DigestMethod dm, List transforms,
String type, String id) {
return new DOMReference(uri, type, dm, transforms, id, getProvider());
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Reference newReference(String uri, DigestMethod dm,
List appliedTransforms, Data result, List transforms, String type,
String id) {
if (appliedTransforms == null) {
throw new NullPointerException("appliedTransforms cannot be null");
}
if (appliedTransforms.isEmpty()) {
throw new NullPointerException("appliedTransforms cannot be empty");
}
if (result == null) {
throw new NullPointerException("result cannot be null");
}
return new DOMReference
(uri, type, dm, appliedTransforms, result, transforms, id, getProvider());
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Reference newReference(String uri, DigestMethod dm, List transforms,
String type, String id, byte[] digestValue) {
if (digestValue == null) {
throw new NullPointerException("digestValue cannot be null");
}
return new DOMReference
(uri, type, dm, null, null, transforms, id, digestValue, getProvider());
}
@SuppressWarnings({ "rawtypes" })
public SignedInfo newSignedInfo(CanonicalizationMethod cm,
SignatureMethod sm, List references) {
return newSignedInfo(cm, sm, references, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SignedInfo newSignedInfo(CanonicalizationMethod cm,
SignatureMethod sm, List references, String id) {
return new DOMSignedInfo(cm, sm, references, id);
}
// Object factory methods
@SuppressWarnings({ "unchecked", "rawtypes" })
public XMLObject newXMLObject(List content, String id, String mimeType,
String encoding) {
return new DOMXMLObject(content, id, mimeType, encoding);
}
@SuppressWarnings({ "rawtypes" })
public Manifest newManifest(List references) {
return newManifest(references, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Manifest newManifest(List references, String id) {
return new DOMManifest(references, id);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SignatureProperties newSignatureProperties(List props, String id) {
return new DOMSignatureProperties(props, id);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SignatureProperty newSignatureProperty
(List info, String target, String id) {
return new DOMSignatureProperty(info, target, id);
}
public XMLSignature unmarshalXMLSignature(XMLValidateContext context)
throws MarshalException {
if (context == null) {
throw new NullPointerException("context cannot be null");
}
return unmarshal(((DOMValidateContext) context).getNode(), context);
}
public XMLSignature unmarshalXMLSignature(XMLStructure xmlStructure)
throws MarshalException {
if (xmlStructure == null) {
throw new NullPointerException("xmlStructure cannot be null");
}
if (!(xmlStructure instanceof javax.xml.crypto.dom.DOMStructure)) {
throw new ClassCastException("xmlStructure must be of type DOMStructure");
}
return unmarshal
(((javax.xml.crypto.dom.DOMStructure) xmlStructure).getNode(),
new UnmarshalContext());
}
private static class UnmarshalContext extends DOMCryptoContext {
UnmarshalContext() {}
}
private XMLSignature unmarshal(Node node, XMLCryptoContext context)
throws MarshalException {
node.normalize();
Element element = null;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
element = ((Document) node).getDocumentElement();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
element = (Element) node;
} else {
throw new MarshalException
("Signature element is not a proper Node");
}
// check tag
String tag = element.getLocalName();
String namespace = element.getNamespaceURI();
if (tag == null || namespace == null) {
throw new MarshalException("Document implementation must " +
"support DOM Level 2 and be namespace aware");
}
if ("Signature".equals(tag) && XMLSignature.XMLNS.equals(namespace)) {
try {
return new DOMXMLSignature(element, context, getProvider());
} catch (MarshalException me) {
throw me;
} catch (Exception e) {
throw new MarshalException(e);
}
} else {
throw new MarshalException("Invalid Signature tag: " + namespace + ":" + tag);
}
}
public boolean isFeatureSupported(String feature) {
if (feature == null) {
throw new NullPointerException();
} else {
return false;
}
}
public DigestMethod newDigestMethod(String algorithm,
DigestMethodParameterSpec params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
if (algorithm == null) {
throw new NullPointerException();
}
if (algorithm.equals(DigestMethod.SHA1)) {
return new DOMDigestMethod.SHA1(params);
} else if (algorithm.equals(DOMDigestMethod.SHA224)) {
return new DOMDigestMethod.SHA224(params);
} else if (algorithm.equals(DigestMethod.SHA256)) {
return new DOMDigestMethod.SHA256(params);
} else if (algorithm.equals(DOMDigestMethod.SHA384)) {
return new DOMDigestMethod.SHA384(params);
} else if (algorithm.equals(DigestMethod.SHA512)) {
return new DOMDigestMethod.SHA512(params);
} else if (algorithm.equals(DigestMethod.RIPEMD160)) {
return new DOMDigestMethod.RIPEMD160(params);
} else {
throw new NoSuchAlgorithmException("unsupported algorithm");
}
}
public SignatureMethod newSignatureMethod(String algorithm,
SignatureMethodParameterSpec params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
if (algorithm == null) {
throw new NullPointerException();
}
if (algorithm.equals(SignatureMethod.RSA_SHA1)) {
return new DOMSignatureMethod.SHA1withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA224)) {
return new DOMSignatureMethod.SHA224withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA256)) {
return new DOMSignatureMethod.SHA256withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA384)) {
return new DOMSignatureMethod.SHA384withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA512)) {
return new DOMSignatureMethod.SHA512withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_RIPEMD160)) {
return new DOMSignatureMethod.RIPEMD160withRSA(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA1_MGF1)) {
return new DOMSignatureMethod.SHA1withRSAandMGF1(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA224_MGF1)) {
return new DOMSignatureMethod.SHA224withRSAandMGF1(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA256_MGF1)) {
return new DOMSignatureMethod.SHA256withRSAandMGF1(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA384_MGF1)) {
return new DOMSignatureMethod.SHA384withRSAandMGF1(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_SHA512_MGF1)) {
return new DOMSignatureMethod.SHA512withRSAandMGF1(params);
} else if (algorithm.equals(DOMSignatureMethod.RSA_RIPEMD160_MGF1)) {
return new DOMSignatureMethod.RIPEMD160withRSAandMGF1(params);
} else if (algorithm.equals(SignatureMethod.DSA_SHA1)) {
return new DOMSignatureMethod.SHA1withDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.DSA_SHA256)) {
return new DOMSignatureMethod.SHA256withDSA(params);
} else if (algorithm.equals(SignatureMethod.HMAC_SHA1)) {
return new DOMHMACSignatureMethod.SHA1(params);
} else if (algorithm.equals(DOMHMACSignatureMethod.HMAC_SHA224)) {
return new DOMHMACSignatureMethod.SHA224(params);
} else if (algorithm.equals(DOMHMACSignatureMethod.HMAC_SHA256)) {
return new DOMHMACSignatureMethod.SHA256(params);
} else if (algorithm.equals(DOMHMACSignatureMethod.HMAC_SHA384)) {
return new DOMHMACSignatureMethod.SHA384(params);
} else if (algorithm.equals(DOMHMACSignatureMethod.HMAC_SHA512)) {
return new DOMHMACSignatureMethod.SHA512(params);
} else if (algorithm.equals(DOMHMACSignatureMethod.HMAC_RIPEMD160)) {
return new DOMHMACSignatureMethod.RIPEMD160(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_SHA1)) {
return new DOMSignatureMethod.SHA1withECDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_SHA224)) {
return new DOMSignatureMethod.SHA224withECDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_SHA256)) {
return new DOMSignatureMethod.SHA256withECDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_SHA384)) {
return new DOMSignatureMethod.SHA384withECDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_SHA512)) {
return new DOMSignatureMethod.SHA512withECDSA(params);
} else if (algorithm.equals(DOMSignatureMethod.ECDSA_RIPEMD160)) {
return new DOMSignatureMethod.RIPEMD160withECDSA(params);
}else {
throw new NoSuchAlgorithmException("unsupported algorithm");
}
}
public Transform newTransform(String algorithm,
TransformParameterSpec params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
TransformService spi;
if (getProvider() == null) {
spi = TransformService.getInstance(algorithm, "DOM");
} else {
try {
spi = TransformService.getInstance(algorithm, "DOM", getProvider());
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(algorithm, "DOM");
}
}
spi.init(params);
return new DOMTransform(spi);
}
public Transform newTransform(String algorithm,
XMLStructure params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
TransformService spi;
if (getProvider() == null) {
spi = TransformService.getInstance(algorithm, "DOM");
} else {
try {
spi = TransformService.getInstance(algorithm, "DOM", getProvider());
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(algorithm, "DOM");
}
}
if (params == null) {
spi.init(null);
} else {
spi.init(params, null);
}
return new DOMTransform(spi);
}
public CanonicalizationMethod newCanonicalizationMethod(String algorithm,
C14NMethodParameterSpec params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
TransformService spi;
if (getProvider() == null) {
spi = TransformService.getInstance(algorithm, "DOM");
} else {
try {
spi = TransformService.getInstance(algorithm, "DOM", getProvider());
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(algorithm, "DOM");
}
}
spi.init(params);
return new DOMCanonicalizationMethod(spi);
}
public CanonicalizationMethod newCanonicalizationMethod(String algorithm,
XMLStructure params) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
TransformService spi;
if (getProvider() == null) {
spi = TransformService.getInstance(algorithm, "DOM");
} else {
try {
spi = TransformService.getInstance(algorithm, "DOM", getProvider());
} catch (NoSuchAlgorithmException nsae) {
spi = TransformService.getInstance(algorithm, "DOM");
}
}
if (params == null) {
spi.init(null);
} else {
spi.init(params, null);
}
return new DOMCanonicalizationMethod(spi);
}
public URIDereferencer getURIDereferencer() {
return DOMURIDereferencer.INSTANCE;
}
}

View File

@@ -0,0 +1,161 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* ===========================================================================
*
* (C) Copyright IBM Corp. 2003 All Rights Reserved.
*
* ===========================================================================
*/
/*
* Portions copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMXPathFilter2Transform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.crypto.dsig.spec.XPathType;
import javax.xml.crypto.dsig.spec.XPathFilter2ParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
* DOM-based implementation of XPath Filter 2.0 Transform.
* (Uses Apache XML-Sec Transform implementation)
*
*/
public final class DOMXPathFilter2Transform extends ApacheTransform {
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params == null) {
throw new InvalidAlgorithmParameterException("params are required");
} else if (!(params instanceof XPathFilter2ParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type XPathFilter2ParameterSpec");
}
this.params = params;
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException
{
super.init(parent, context);
try {
unmarshalParams(DOMUtils.getFirstChildElement(transformElem));
} catch (MarshalException me) {
throw new InvalidAlgorithmParameterException(me);
}
}
private void unmarshalParams(Element curXPathElem) throws MarshalException
{
List<XPathType> list = new ArrayList<>();
Element currentElement = curXPathElem;
while (currentElement != null) {
String xPath = currentElement.getFirstChild().getNodeValue();
String filterVal = DOMUtils.getAttributeValue(currentElement,
"Filter");
if (filterVal == null) {
throw new MarshalException("filter cannot be null");
}
XPathType.Filter filter = null;
if ("intersect".equals(filterVal)) {
filter = XPathType.Filter.INTERSECT;
} else if ("subtract".equals(filterVal)) {
filter = XPathType.Filter.SUBTRACT;
} else if ("union".equals(filterVal)) {
filter = XPathType.Filter.UNION;
} else {
throw new MarshalException("Unknown XPathType filter type" +
filterVal);
}
NamedNodeMap attributes = currentElement.getAttributes();
if (attributes != null) {
int length = attributes.getLength();
Map<String, String> namespaceMap =
new HashMap<>(length);
for (int i = 0; i < length; i++) {
Attr attr = (Attr)attributes.item(i);
String prefix = attr.getPrefix();
if (prefix != null && "xmlns".equals(prefix)) {
namespaceMap.put(attr.getLocalName(), attr.getValue());
}
}
list.add(new XPathType(xPath, filter, namespaceMap));
} else {
list.add(new XPathType(xPath, filter));
}
currentElement = DOMUtils.getNextSiblingElement(currentElement);
}
this.params = new XPathFilter2ParameterSpec(list);
}
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
super.marshalParams(parent, context);
XPathFilter2ParameterSpec xp =
(XPathFilter2ParameterSpec)getParameterSpec();
String prefix = DOMUtils.getNSPrefix(context, Transform.XPATH2);
String qname = prefix == null || prefix.length() == 0
? "xmlns" : "xmlns:" + prefix;
@SuppressWarnings("unchecked")
List<XPathType> xpathList = xp.getXPathList();
for (XPathType xpathType : xpathList) {
Element elem = DOMUtils.createElement(ownerDoc, "XPath",
Transform.XPATH2, prefix);
elem.appendChild
(ownerDoc.createTextNode(xpathType.getExpression()));
DOMUtils.setAttribute(elem, "Filter",
xpathType.getFilter().toString());
elem.setAttributeNS("http://www.w3.org/2000/xmlns/", qname,
Transform.XPATH2);
// add namespace attributes, if necessary
@SuppressWarnings("unchecked")
Set<Map.Entry<String, String>> entries =
xpathType.getNamespaceMap().entrySet();
for (Map.Entry<String, String> entry : entries) {
elem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" +
entry.getKey(),
entry.getValue());
}
transformElem.appendChild(elem);
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMXPathTransform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
* DOM-based implementation of XPath Filtering Transform.
* (Uses Apache XML-Sec Transform implementation)
*
*/
public final class DOMXPathTransform extends ApacheTransform {
@Override
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException
{
if (params == null) {
throw new InvalidAlgorithmParameterException("params are required");
} else if (!(params instanceof XPathFilterParameterSpec)) {
throw new InvalidAlgorithmParameterException
("params must be of type XPathFilterParameterSpec");
}
this.params = params;
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException
{
super.init(parent, context);
unmarshalParams(DOMUtils.getFirstChildElement(transformElem));
}
private void unmarshalParams(Element paramsElem) {
String xPath = paramsElem.getFirstChild().getNodeValue();
// create a Map of namespace prefixes
NamedNodeMap attributes = paramsElem.getAttributes();
if (attributes != null) {
int length = attributes.getLength();
Map<String, String> namespaceMap =
new HashMap<>(length);
for (int i = 0; i < length; i++) {
Attr attr = (Attr)attributes.item(i);
String prefix = attr.getPrefix();
if (prefix != null && "xmlns".equals(prefix)) {
namespaceMap.put(attr.getLocalName(), attr.getValue());
}
}
this.params = new XPathFilterParameterSpec(xPath, namespaceMap);
} else {
this.params = new XPathFilterParameterSpec(xPath);
}
}
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException
{
super.marshalParams(parent, context);
XPathFilterParameterSpec xp =
(XPathFilterParameterSpec)getParameterSpec();
Element xpathElem = DOMUtils.createElement(ownerDoc, "XPath",
XMLSignature.XMLNS, DOMUtils.getSignaturePrefix(context));
xpathElem.appendChild(ownerDoc.createTextNode(xp.getXPath()));
// add namespace attributes, if necessary
@SuppressWarnings("unchecked")
Set<Map.Entry<String, String>> entries =
xp.getNamespaceMap().entrySet();
for (Map.Entry<String, String> entry : entries) {
xpathElem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" +
entry.getKey(),
entry.getValue());
}
transformElem.appendChild(xpathElem);
}
}

View File

@@ -0,0 +1,79 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: DOMXSLTTransform.java 1854026 2019-02-21 09:30:01Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.security.InvalidAlgorithmParameterException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.crypto.dsig.spec.XSLTTransformParameterSpec;
/**
* DOM-based implementation of XSLT Transform.
* (Uses Apache XML-Sec Transform implementation)
*
*/
public final class DOMXSLTTransform extends ApacheTransform {
@Override
public void init(TransformParameterSpec params)
throws InvalidAlgorithmParameterException {
if (params == null) {
throw new InvalidAlgorithmParameterException("params are required");
}
if (!(params instanceof XSLTTransformParameterSpec)) {
throw new InvalidAlgorithmParameterException("unrecognized params");
}
this.params = params;
}
public void init(XMLStructure parent, XMLCryptoContext context)
throws InvalidAlgorithmParameterException {
super.init(parent, context);
unmarshalParams(DOMUtils.getFirstChildElement(transformElem));
}
private void unmarshalParams(Element sheet) {
this.params = new XSLTTransformParameterSpec
(new javax.xml.crypto.dom.DOMStructure(sheet));
}
public void marshalParams(XMLStructure parent, XMLCryptoContext context)
throws MarshalException {
super.marshalParams(parent, context);
XSLTTransformParameterSpec xp =
(XSLTTransformParameterSpec) getParameterSpec();
Node xsltElem =
((javax.xml.crypto.dom.DOMStructure) xp.getStylesheet()).getNode();
DOMUtils.appendChild(transformElem, xsltElem);
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.jcp.xml.dsig.internal.dom;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Security;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* The secure validation policy as specified by the
* jdk.xml.dsig.secureValidationPolicy security property.
*/
public final class Policy {
// all restrictions are initialized to be unconstrained
private static Set<URI> disallowedAlgs = new HashSet<>();
private static int maxTrans = Integer.MAX_VALUE;
private static int maxRefs = Integer.MAX_VALUE;
private static Set<String> disallowedRefUriSchemes = new HashSet<>();
private static Map<String, Integer> minKeyMap = new HashMap<>();
private static boolean noDuplicateIds = false;
private static boolean noRMLoops = false;
static {
try {
initialize();
} catch (Exception e) {
throw new SecurityException(
"Cannot initialize the secure validation policy", e);
}
}
private Policy() {}
private static void initialize() {
String prop =
AccessController.doPrivileged((PrivilegedAction<String>) () ->
Security.getProperty("jdk.xml.dsig.secureValidationPolicy"));
if (prop == null || prop.isEmpty()) {
// no policy specified, so don't enforce any restrictions
return;
}
String[] entries = prop.split(",");
for (String entry : entries) {
String[] tokens = entry.split("\\s");
String type = tokens[0];
switch(type) {
case "disallowAlg":
if (tokens.length != 2) {
error(entry);
}
disallowedAlgs.add(URI.create(tokens[1]));
break;
case "maxTransforms":
if (tokens.length != 2) {
error(entry);
}
maxTrans = Integer.parseUnsignedInt(tokens[1]);
break;
case "maxReferences":
if (tokens.length != 2) {
error(entry);
}
maxRefs = Integer.parseUnsignedInt(tokens[1]);
break;
case "disallowReferenceUriSchemes":
if (tokens.length == 1) {
error(entry);
}
for (int i = 1; i < tokens.length; i++) {
String scheme = tokens[i];
disallowedRefUriSchemes.add(
scheme.toLowerCase(Locale.ROOT));
}
break;
case "minKeySize":
if (tokens.length != 3) {
error(entry);
}
minKeyMap.put(tokens[1],
Integer.parseUnsignedInt(tokens[2]));
break;
case "noDuplicateIds":
if (tokens.length != 1) {
error(entry);
}
noDuplicateIds = true;
break;
case "noRetrievalMethodLoops":
if (tokens.length != 1) {
error(entry);
}
noRMLoops = true;
break;
default:
error(entry);
}
}
}
public static boolean restrictAlg(String alg) {
try {
URI uri = new URI(alg);
return disallowedAlgs.contains(uri);
} catch (URISyntaxException use) {
return false;
}
}
public static boolean restrictNumTransforms(int numTrans) {
return (numTrans > maxTrans);
}
public static boolean restrictNumReferences(int numRefs) {
return (numRefs > maxRefs);
}
public static boolean restrictReferenceUriScheme(String uri) {
if (uri != null) {
String scheme = java.net.URI.create(uri).getScheme();
if (scheme != null) {
return disallowedRefUriSchemes.contains(
scheme.toLowerCase(Locale.ROOT));
}
}
return false;
}
public static boolean restrictKey(String type, int size) {
return (size < minKeyMap.getOrDefault(type, 0));
}
public static boolean restrictDuplicateIds() {
return noDuplicateIds;
}
public static boolean restrictRetrievalMethodLoops() {
return noRMLoops;
}
public static Set<URI> disabledAlgs() {
return Collections.<URI>unmodifiableSet(disallowedAlgs);
}
public static int maxTransforms() {
return maxTrans;
}
public static int maxReferences() {
return maxRefs;
}
public static Set<String> disabledReferenceUriSchemes() {
return Collections.<String>unmodifiableSet(disallowedRefUriSchemes);
}
public static int minKeySize(String type) {
return minKeyMap.getOrDefault(type, 0);
}
private static void error(String entry) {
throw new IllegalArgumentException(
"Invalid jdk.xml.dsig.secureValidationPolicy entry: " + entry);
}
}

View File

@@ -0,0 +1,123 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: Utils.java 1788465 2017-03-24 15:10:51Z coheigea $
*/
package org.jcp.xml.dsig.internal.dom;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.*;
import javax.xml.crypto.XMLCryptoContext;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* Miscellaneous static utility methods for use in JSR 105 RI.
*
*/
public final class Utils {
private Utils() {}
public static byte[] readBytesFromStream(InputStream is)
throws IOException
{
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buf = new byte[1024];
while (true) {
int read = is.read(buf);
if (read == -1) { // EOF
break;
}
baos.write(buf, 0, read);
if (read < 1024) {
break;
}
}
return baos.toByteArray();
}
}
/**
* Converts an Iterator to a Set of Nodes, according to the XPath
* Data Model.
*
* @param i the Iterator
* @return the Set of Nodes
*/
static Set<Node> toNodeSet(Iterator<Node> i) {
Set<Node> nodeSet = new HashSet<>();
while (i.hasNext()) {
Node n = i.next();
nodeSet.add(n);
// insert attributes nodes to comply with XPath
if (n.getNodeType() == Node.ELEMENT_NODE) {
NamedNodeMap nnm = n.getAttributes();
for (int j = 0, length = nnm.getLength(); j < length; j++) {
nodeSet.add(nnm.item(j));
}
}
}
return nodeSet;
}
/**
* Returns the ID from a same-document URI (ex: "#id")
*/
public static String parseIdFromSameDocumentURI(String uri) {
if (uri.length() == 0) {
return null;
}
String id = uri.substring(1);
if (id != null && id.startsWith("xpointer(id(")) {
int i1 = id.indexOf('\'');
int i2 = id.indexOf('\'', i1+1);
id = id.substring(i1+1, i2);
}
return id;
}
/**
* Returns true if uri is a same-document URI, false otherwise.
*/
public static boolean sameDocumentURI(String uri) {
return uri != null && (uri.length() == 0 || uri.charAt(0) == '#');
}
static boolean secureValidation(XMLCryptoContext xc) {
if (xc == null) {
return false;
}
return getBoolean(xc, "org.jcp.xml.dsig.secureValidation");
}
private static boolean getBoolean(XMLCryptoContext xc, String name) {
Boolean value = (Boolean)xc.getProperty(name);
return value != null && value.booleanValue();
}
}

View File

@@ -0,0 +1,161 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/**
* 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.
*/
/*
* ===========================================================================
*
* (C) Copyright IBM Corp. 2003 All Rights Reserved.
*
* ===========================================================================
*/
/*
* Portions copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
*/
/*
* $Id: XMLDSigRI.java 1833618 2018-06-15 17:36:20Z mullan $
*/
package org.jcp.xml.dsig.internal.dom;
import java.util.*;
import java.security.*;
import javax.xml.crypto.dsig.*;
/**
* The XMLDSig RI Provider.
*
*/
/**
* Defines the XMLDSigRI provider.
*/
public final class XMLDSigRI extends Provider {
static final long serialVersionUID = -5049765099299494554L;
private static final String INFO = "XMLDSig " +
"(DOM XMLSignatureFactory; DOM KeyInfoFactory; " +
"C14N 1.0, C14N 1.1, Exclusive C14N, Base64, Enveloped, XPath, " +
"XPath2, XSLT TransformServices)";
public XMLDSigRI() {
/* We are the XMLDSig provider */
super("XMLDSig", 1.8d, INFO);
final Map<Object, Object> map = new HashMap<Object, Object>();
map.put("XMLSignatureFactory.DOM",
"org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory");
map.put("KeyInfoFactory.DOM",
"org.jcp.xml.dsig.internal.dom.DOMKeyInfoFactory");
// Inclusive C14N
map.put("TransformService." + CanonicalizationMethod.INCLUSIVE,
"org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14NMethod");
map.put("Alg.Alias.TransformService.INCLUSIVE",
CanonicalizationMethod.INCLUSIVE);
map.put("TransformService." + CanonicalizationMethod.INCLUSIVE +
" MechanismType", "DOM");
// InclusiveWithComments C14N
map.put("TransformService." +
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
"org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14NMethod");
map.put("Alg.Alias.TransformService.INCLUSIVE_WITH_COMMENTS",
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS);
map.put("TransformService." +
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS +
" MechanismType", "DOM");
// Inclusive C14N 1.1
map.put("TransformService.http://www.w3.org/2006/12/xml-c14n11",
"org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14N11Method");
map.put("TransformService.http://www.w3.org/2006/12/xml-c14n11" +
" MechanismType", "DOM");
// InclusiveWithComments C14N 1.1
map.put("TransformService.http://www.w3.org/2006/12/xml-c14n11#WithComments",
"org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14N11Method");
map.put("TransformService.http://www.w3.org/2006/12/xml-c14n11#WithComments" +
" MechanismType", "DOM");
// Exclusive C14N
map.put("TransformService." + CanonicalizationMethod.EXCLUSIVE,
"org.jcp.xml.dsig.internal.dom.DOMExcC14NMethod");
map.put("Alg.Alias.TransformService.EXCLUSIVE",
CanonicalizationMethod.EXCLUSIVE);
map.put("TransformService." + CanonicalizationMethod.EXCLUSIVE +
" MechanismType", "DOM");
// ExclusiveWithComments C14N
map.put("TransformService." +
CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS,
"org.jcp.xml.dsig.internal.dom.DOMExcC14NMethod");
map.put("Alg.Alias.TransformService.EXCLUSIVE_WITH_COMMENTS",
CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS);
map.put("TransformService." +
CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS +
" MechanismType", "DOM");
// Base64 Transform
map.put("TransformService." + Transform.BASE64,
"org.jcp.xml.dsig.internal.dom.DOMBase64Transform");
map.put("Alg.Alias.TransformService.BASE64", Transform.BASE64);
map.put("TransformService." + Transform.BASE64 +
" MechanismType", "DOM");
// Enveloped Transform
map.put("TransformService." + Transform.ENVELOPED,
"org.jcp.xml.dsig.internal.dom.DOMEnvelopedTransform");
map.put("Alg.Alias.TransformService.ENVELOPED", Transform.ENVELOPED);
map.put("TransformService." + Transform.ENVELOPED +
" MechanismType", "DOM");
// XPath2 Transform
map.put("TransformService." + Transform.XPATH2,
"org.jcp.xml.dsig.internal.dom.DOMXPathFilter2Transform");
map.put("Alg.Alias.TransformService.XPATH2", Transform.XPATH2);
map.put("TransformService." + Transform.XPATH2 +
" MechanismType", "DOM");
// XPath Transform
map.put("TransformService." + Transform.XPATH,
"org.jcp.xml.dsig.internal.dom.DOMXPathTransform");
map.put("Alg.Alias.TransformService.XPATH", Transform.XPATH);
map.put("TransformService." + Transform.XPATH +
" MechanismType", "DOM");
// XSLT Transform
map.put("TransformService." + Transform.XSLT,
"org.jcp.xml.dsig.internal.dom.DOMXSLTTransform");
map.put("Alg.Alias.TransformService.XSLT", Transform.XSLT);
map.put("TransformService." + Transform.XSLT + " MechanismType", "DOM");
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
putAll(map);
return null;
}
});
}
}