# HG changeset patch # User weijun # Date 1570718198 -10800 # Node ID b3116877866fa54c50e3cd8af97d0b8b4c61b3af # Parent 9fe5d0d4e9c58eb6b7857dc66f03a84b17ce2bec 8231507: Update Apache Santuario (XML Signature) to version 2.1.4 Reviewed-by: weijun Contributed-by: fedor.burdun@azulsystems.com, weijun.wang@oracle.com diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/Init.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/Init.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/Init.java Thu Oct 10 17:36:38 2019 +0300 @@ -30,8 +30,6 @@ import java.util.ArrayList; import java.util.List; -import javax.xml.parsers.DocumentBuilder; - import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper; import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm; import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; @@ -170,8 +168,7 @@ private static void fileInit(InputStream is) { try { /* read library configuration file */ - DocumentBuilder db = XMLUtils.createDocumentBuilder(false); - Document doc = db.parse(is); + Document doc = XMLUtils.read(is, false); Node config = doc.getFirstChild(); for (; config != null; config = config.getNextSibling()) { if ("Configuration".equals(config.getLocalName())) { diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java Thu Oct 10 17:36:38 2019 +0300 @@ -30,8 +30,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import javax.xml.parsers.DocumentBuilder; - import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_OmitComments; import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_WithComments; import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315ExclOmitComments; @@ -261,17 +259,7 @@ try (InputStream bais = new ByteArrayInputStream(inputBytes)) { InputSource in = new InputSource(bais); - // needs to validate for ID attribute normalization - DocumentBuilder db = XMLUtils.createDocumentBuilder(true, secureValidation); - /* - * for some of the test vectors from the specification, - * there has to be a validating parser for ID attributes, default - * attribute values, NMTOKENS, etc. - * Unfortunately, the test vectors do use different DTDs or - * even no DTD. So Xerces 1.3.1 fires many warnings about using - * ErrorHandlers. - * * Text from the spec: * * The input octet stream MUST contain a well-formed XML document, @@ -285,9 +273,7 @@ * though the document type declaration is not retained in the * canonical form. */ - db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils.IgnoreAllErrorHandler()); - - document = db.parse(in); + document = XMLUtils.read(in, secureValidation); } return this.canonicalizeSubtree(document); } diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizerSpi.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizerSpi.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizerSpi.java Thu Oct 10 17:36:38 2019 +0300 @@ -26,8 +26,6 @@ import java.io.OutputStream; import java.util.Set; -import javax.xml.parsers.DocumentBuilder; - import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -63,9 +61,7 @@ try (java.io.InputStream bais = new ByteArrayInputStream(inputBytes)) { InputSource in = new InputSource(bais); - DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation); - - document = db.parse(in); + document = XMLUtils.read(in, secureValidation); } return this.engineCanonicalizeSubTree(document); } diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java Thu Oct 10 17:36:38 2019 +0300 @@ -31,7 +31,6 @@ import java.util.HashMap; import javax.crypto.SecretKey; -import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver; @@ -276,10 +275,8 @@ * @throws KeyResolverException if something goes wrong */ protected static Element getDocFromBytes(byte[] bytes, boolean secureValidation) throws KeyResolverException { - DocumentBuilder db = null; try (InputStream is = new ByteArrayInputStream(bytes)) { - db = XMLUtils.createDocumentBuilder(false, secureValidation); - Document doc = db.parse(is); + Document doc = XMLUtils.read(is, secureValidation); return doc.getDocumentElement(); } catch (SAXException ex) { throw new KeyResolverException(ex); diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/SignedInfo.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/SignedInfo.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/SignedInfo.java Thu Oct 10 17:36:38 2019 +0300 @@ -215,10 +215,8 @@ c14nizer.setSecureValidation(secureValidation); byte[] c14nizedBytes = c14nizer.canonicalizeSubtree(element); - javax.xml.parsers.DocumentBuilder db = - XMLUtils.createDocumentBuilder(false, secureValidation); try (InputStream is = new ByteArrayInputStream(c14nizedBytes)) { - Document newdoc = db.parse(is); + Document newdoc = XMLUtils.read(is, secureValidation); Node imported = element.getOwnerDocument().importNode( newdoc.getDocumentElement(), true); element.getParentNode().replaceChild(imported, element); diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/XMLSignatureInput.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/XMLSignatureInput.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/XMLSignatureInput.java Thu Oct 10 17:36:38 2019 +0300 @@ -33,7 +33,6 @@ import java.util.List; import java.util.Set; -import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; @@ -574,12 +573,9 @@ void convertToNodes() throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { - DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation); // select all nodes, also the comments. try { - db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils.IgnoreAllErrorHandler()); - - Document doc = db.parse(this.getOctetStream()); + Document doc = XMLUtils.read(this.getOctetStream(), secureValidation); this.subNode = doc; } catch (SAXException ex) { byte[] result = null; @@ -593,7 +589,7 @@ result = baos.toByteArray(); } try (InputStream is = new ByteArrayInputStream(result)) { - Document document = db.parse(is); + Document document = XMLUtils.read(is, secureValidation); this.subNode = document.getDocumentElement().getFirstChild().getFirstChild(); } } finally { diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/implementations/TransformBase64Decode.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/implementations/TransformBase64Decode.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/implementations/TransformBase64Decode.java Thu Oct 10 17:36:38 2019 +0300 @@ -147,7 +147,7 @@ //Exceptional case there is current not text case testing this(Before it was a //a common case). Document doc = - XMLUtils.createDocumentBuilder(false, secureValidation).parse(input.getOctetStream()); + XMLUtils.read(input.getOctetStream(), secureValidation); Element rootNode = doc.getDocumentElement(); StringBuilder sb = new StringBuilder(); diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/WeakObjectPool.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/WeakObjectPool.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/WeakObjectPool.java Thu Oct 10 17:36:38 2019 +0300 @@ -39,7 +39,10 @@ * * Internally, the pool is stored in a java.util.concurrent.LinkedBlockingDeque * instance. + * + * @deprecated This class is no longer in use in Santuario 2.1.4 */ +@Deprecated public abstract class WeakObjectPool { private static final Integer MARKER_VALUE = Integer.MAX_VALUE;//once here rather than auto-box it? diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/XMLUtils.java --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/XMLUtils.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/XMLUtils.java Thu Oct 10 17:36:38 2019 +0300 @@ -23,16 +23,22 @@ package com.sun.org.apache.xml.internal.security.utils; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Queue; import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ArrayBlockingQueue; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -48,6 +54,8 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; /** * DOM and XML accessibility and comfort functions. @@ -58,6 +66,9 @@ private static boolean ignoreLineBreaks = AccessController.doPrivileged( (PrivilegedAction) () -> Boolean.getBoolean("com.sun.org.apache.xml.internal.security.ignoreLineBreaks")); + private static int parserPoolSize = + AccessController.doPrivileged( + (PrivilegedAction) () -> Integer.getInteger("com.sun.org.apache.xml.internal.security.parser.pool-size", 20)); private static volatile String dsPrefix = "ds"; private static volatile String ds11Prefix = "dsig11"; @@ -67,6 +78,11 @@ private static final com.sun.org.slf4j.internal.Logger LOG = com.sun.org.slf4j.internal.LoggerFactory.getLogger(XMLUtils.class); + private static final Map> DOCUMENT_BUILDERS = + Collections.synchronizedMap(new WeakHashMap>()); + + private static final Map> DOCUMENT_BUILDERS_DISALLOW_DOCTYPE = + Collections.synchronizedMap(new WeakHashMap>()); /** * Constructor XMLUtils @@ -147,7 +163,7 @@ if (rootNode == exclude) { return; } - switch (rootNode.getNodeType()) { + switch (rootNode.getNodeType()) { //NOPMD case Node.ELEMENT_NODE: result.add(rootNode); Element el = (Element)rootNode; @@ -172,20 +188,19 @@ } getSetRec(r, result, exclude, com); } - return; + break; case Node.COMMENT_NODE: if (com) { result.add(rootNode); } - return; + break; case Node.DOCUMENT_TYPE_NODE: - return; + break; default: result.add(rootNode); } } - /** * Outputs a DOM tree to an {@link OutputStream}. * @@ -960,18 +975,105 @@ return true; } - public static DocumentBuilder createDocumentBuilder(boolean validating) - throws ParserConfigurationException { + public static Document newDocument() throws ParserConfigurationException { + ClassLoader loader = getContextClassLoader(); + if (loader == null) { + loader = getClassLoader(XMLUtils.class); + } + // If the ClassLoader is null then just create a DocumentBuilder and use it + if (loader == null) { + DocumentBuilder documentBuilder = buildDocumentBuilder(true); + return documentBuilder.newDocument(); + } + + Queue queue = getDocumentBuilderQueue(true, loader); + DocumentBuilder documentBuilder = getDocumentBuilder(true, queue); + Document doc = documentBuilder.newDocument(); + repoolDocumentBuilder(documentBuilder, queue); + return doc; + } + + public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException { + return read(inputStream, true); + } + + public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException, SAXException, IOException { + ClassLoader loader = getContextClassLoader(); + if (loader == null) { + loader = getClassLoader(XMLUtils.class); + } + // If the ClassLoader is null then just create a DocumentBuilder and use it + if (loader == null) { + DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations); + return documentBuilder.parse(inputStream); + } + + Queue queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader); + DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue); + Document doc = documentBuilder.parse(inputStream); + repoolDocumentBuilder(documentBuilder, queue); + return doc; + } + + public static Document read(String uri, boolean disAllowDocTypeDeclarations) + throws ParserConfigurationException, SAXException, IOException { + ClassLoader loader = getContextClassLoader(); + if (loader == null) { + loader = getClassLoader(XMLUtils.class); + } + // If the ClassLoader is null then just create a DocumentBuilder and use it + if (loader == null) { + DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations); + return documentBuilder.parse(uri); + } + + Queue queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader); + DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue); + Document doc = documentBuilder.parse(uri); + repoolDocumentBuilder(documentBuilder, queue); + return doc; + } + + public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException { + return read(inputSource, true); + } + + public static Document read(InputSource inputSource, boolean disAllowDocTypeDeclarations) + throws ParserConfigurationException, SAXException, IOException { + ClassLoader loader = getContextClassLoader(); + if (loader == null) { + loader = getClassLoader(XMLUtils.class); + } + // If the ClassLoader is null then just create a DocumentBuilder and use it + if (loader == null) { + DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations); + return documentBuilder.parse(inputSource); + } + + Queue queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader); + DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue); + Document doc = documentBuilder.parse(inputSource); + repoolDocumentBuilder(documentBuilder, queue); + return doc; + } + + /** + * @deprecated Use XMLUtils.read instead to directly read a document. + */ + @Deprecated + public static DocumentBuilder createDocumentBuilder(boolean validating) throws ParserConfigurationException { return createDocumentBuilder(validating, true); } - // The current implementation does not throw a ParserConfigurationException. - // Kept here in case we create the DocumentBuilder inline again. + /** + * @deprecated Use XMLUtils.read instead to directly read a document. + */ + @Deprecated public static DocumentBuilder createDocumentBuilder( boolean validating, boolean disAllowDocTypeDeclarations ) throws ParserConfigurationException { DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); - dfactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true); + dfactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); if (disAllowDocTypeDeclarations) { dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); } @@ -981,6 +1083,14 @@ } /** + * @deprecated This method has no effect in Santuario 2.1.4 + */ + @Deprecated + public static boolean repoolDocumentBuilder(DocumentBuilder db) { + return true; + } + + /** * Returns a byte-array representation of a {@code {@link BigInteger}}. * No sign-bit is output. * @@ -1024,4 +1134,64 @@ return resizedBytes; } + + private static Queue getDocumentBuilderQueue(boolean disAllowDocTypeDeclarations, ClassLoader loader) throws ParserConfigurationException { + Map> docBuilderCache = + disAllowDocTypeDeclarations ? DOCUMENT_BUILDERS_DISALLOW_DOCTYPE : DOCUMENT_BUILDERS; + Queue queue = docBuilderCache.get(loader); + if (queue == null) { + queue = new ArrayBlockingQueue<>(parserPoolSize); + docBuilderCache.put(loader, queue); + } + + return queue; + } + + private static DocumentBuilder getDocumentBuilder(boolean disAllowDocTypeDeclarations, Queue queue) throws ParserConfigurationException { + DocumentBuilder db = queue.poll(); + if (db == null) { + db = buildDocumentBuilder(disAllowDocTypeDeclarations); + } + return db; + } + + private static DocumentBuilder buildDocumentBuilder(boolean disAllowDocTypeDeclarations) throws ParserConfigurationException { + DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); + f.setNamespaceAware(true); + f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true); + f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations); + return f.newDocumentBuilder(); + } + + private static void repoolDocumentBuilder(DocumentBuilder db, Queue queue) { + if (queue != null) { + db.reset(); + queue.offer(db); + } + } + + private static ClassLoader getContextClassLoader() { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } + return Thread.currentThread().getContextClassLoader(); + } + + private static ClassLoader getClassLoader(final Class clazz) { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + } + return clazz.getClassLoader(); + } + } diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java Thu Oct 10 17:36:38 2019 +0300 @@ -31,7 +31,7 @@ * =========================================================================== */ /* - * $Id: DOMRetrievalMethod.java 1854026 2019-02-21 09:30:01Z coheigea $ + * $Id: DOMRetrievalMethod.java 1862080 2019-06-25 16:50:17Z coheigea $ */ package org.jcp.xml.dsig.internal.dom; @@ -57,7 +57,6 @@ 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; @@ -275,12 +274,10 @@ 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); + Document doc = XMLUtils.read(is, secVal); Element kiElem = doc.getDocumentElement(); if (kiElem.getLocalName().equals("X509Data") && XMLSignature.XMLNS.equals(kiElem.getNamespaceURI())) { diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java Thu Oct 10 17:36:38 2019 +0300 @@ -135,7 +135,7 @@ public XMLDSigRI() { // This is the JDK XMLDSig provider, synced from - // Apache Santuario XML Security for Java, version 2.1.3 + // Apache Santuario XML Security for Java, version 2.1.4 super("XMLDSig", VER, INFO); final Provider p = this; diff -r 9fe5d0d4e9c5 -r b3116877866f src/java.xml.crypto/share/legal/santuario.md --- a/src/java.xml.crypto/share/legal/santuario.md Sun Nov 24 01:03:33 2019 +0100 +++ b/src/java.xml.crypto/share/legal/santuario.md Thu Oct 10 17:36:38 2019 +0300 @@ -1,4 +1,4 @@ -## Apache Santuario v2.1.3 +## Apache Santuario v2.1.4 ### Apache Santuario Notice