1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /** 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 package com.sun.org.apache.xml.internal.security.c14n.implementations; 24 25 import java.io.IOException; 26 import java.io.OutputStream; 27 import java.util.Map; 28 import java.util.Set; 29 import java.util.SortedSet; 30 import java.util.TreeSet; 31 32 import javax.xml.parsers.ParserConfigurationException; 33 34 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; 35 import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; 36 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; 37 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 38 import org.w3c.dom.Attr; 39 import org.w3c.dom.DOMException; 40 import org.w3c.dom.Document; 41 import org.w3c.dom.Element; 42 import org.w3c.dom.NamedNodeMap; 43 import org.w3c.dom.Node; 44 import org.xml.sax.SAXException; 45 46 /** 47 * Implements <A HREF="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">Canonical 48 * XML Version 1.0</A>, a W3C Recommendation from 15 March 2001. 49 * 50 */ 51 public abstract class Canonicalizer20010315 extends CanonicalizerBase { 52 53 private boolean firstCall = true; 54 55 private final XmlAttrStack xmlattrStack; 56 private final boolean c14n11; 57 58 /** 59 * Constructor Canonicalizer20010315 60 * 61 * @param includeComments 62 */ Canonicalizer20010315(boolean includeComments)63 public Canonicalizer20010315(boolean includeComments) { 64 this(includeComments, false); 65 } 66 67 /** 68 * Constructor Canonicalizer20010315 69 * 70 * @param includeComments 71 * @param c14n11 Whether this is a Canonical XML 1.1 implementation or not 72 */ Canonicalizer20010315(boolean includeComments, boolean c14n11)73 public Canonicalizer20010315(boolean includeComments, boolean c14n11) { 74 super(includeComments); 75 xmlattrStack = new XmlAttrStack(c14n11); 76 this.c14n11 = c14n11; 77 } 78 79 80 /** 81 * Always throws a CanonicalizationException because this is inclusive c14n. 82 * 83 * @param xpathNodeSet 84 * @param inclusiveNamespaces 85 * @return none it always fails 86 * @throws CanonicalizationException always 87 */ engineCanonicalizeXPathNodeSet(Set<Node> xpathNodeSet, String inclusiveNamespaces)88 public byte[] engineCanonicalizeXPathNodeSet(Set<Node> xpathNodeSet, String inclusiveNamespaces) 89 throws CanonicalizationException { 90 91 /** $todo$ well, should we throw UnsupportedOperationException ? */ 92 throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation"); 93 } 94 95 /** 96 * Always throws a CanonicalizationException because this is inclusive c14n. 97 * 98 * @param rootNode 99 * @param inclusiveNamespaces 100 * @return none it always fails 101 * @throws CanonicalizationException 102 */ engineCanonicalizeSubTree(Node rootNode, String inclusiveNamespaces)103 public byte[] engineCanonicalizeSubTree(Node rootNode, String inclusiveNamespaces) 104 throws CanonicalizationException { 105 106 /** $todo$ well, should we throw UnsupportedOperationException ? */ 107 throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation"); 108 } 109 110 /** 111 * Always throws a CanonicalizationException because this is inclusive c14n. 112 * 113 * @param rootNode 114 * @param inclusiveNamespaces 115 * @return none it always fails 116 * @throws CanonicalizationException 117 */ engineCanonicalizeSubTree( Node rootNode, String inclusiveNamespaces, boolean propagateDefaultNamespace)118 public byte[] engineCanonicalizeSubTree( 119 Node rootNode, String inclusiveNamespaces, boolean propagateDefaultNamespace) 120 throws CanonicalizationException { 121 122 /** $todo$ well, should we throw UnsupportedOperationException ? */ 123 throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation"); 124 } 125 126 /** 127 * Output the Attr[]s for the given element. 128 * <br> 129 * The code of this method is a copy of {@link #outputAttributes(Element, 130 * NameSpaceSymbTable, Map<String, byte[]>)}, 131 * whereas it takes into account that subtree-c14n is -- well -- subtree-based. 132 * So if the element in question isRoot of c14n, it's parent is not in the 133 * node set, as well as all other ancestors. 134 * 135 * @param element 136 * @param ns 137 * @param cache 138 * @throws CanonicalizationException, DOMException, IOException 139 */ 140 @Override outputAttributesSubtree(Element element, NameSpaceSymbTable ns, Map<String, byte[]> cache)141 protected void outputAttributesSubtree(Element element, NameSpaceSymbTable ns, 142 Map<String, byte[]> cache) 143 throws CanonicalizationException, DOMException, IOException { 144 if (!element.hasAttributes() && !firstCall) { 145 return; 146 } 147 // result will contain the attrs which have to be output 148 SortedSet<Attr> result = new TreeSet<Attr>(COMPARE); 149 150 if (element.hasAttributes()) { 151 NamedNodeMap attrs = element.getAttributes(); 152 int attrsLength = attrs.getLength(); 153 154 for (int i = 0; i < attrsLength; i++) { 155 Attr attribute = (Attr) attrs.item(i); 156 String NUri = attribute.getNamespaceURI(); 157 String NName = attribute.getLocalName(); 158 String NValue = attribute.getValue(); 159 160 if (!XMLNS_URI.equals(NUri)) { 161 //It's not a namespace attr node. Add to the result and continue. 162 result.add(attribute); 163 } else if (!(XML.equals(NName) && XML_LANG_URI.equals(NValue))) { 164 //The default mapping for xml must not be output. 165 Node n = ns.addMappingAndRender(NName, NValue, attribute); 166 167 if (n != null) { 168 //Render the ns definition 169 result.add((Attr)n); 170 if (C14nHelper.namespaceIsRelative(attribute)) { 171 Object exArgs[] = { element.getTagName(), NName, attribute.getNodeValue() }; 172 throw new CanonicalizationException( 173 "c14n.Canonicalizer.RelativeNamespace", exArgs 174 ); 175 } 176 } 177 } 178 } 179 } 180 181 if (firstCall) { 182 //It is the first node of the subtree 183 //Obtain all the namespaces defined in the parents, and added to the output. 184 ns.getUnrenderedNodes(result); 185 //output the attributes in the xml namespace. 186 xmlattrStack.getXmlnsAttr(result); 187 firstCall = false; 188 } 189 190 OutputStream writer = getWriter(); 191 //we output all Attrs which are available 192 for (Attr attr : result) { 193 outputAttrToWriter(attr.getNodeName(), attr.getNodeValue(), writer, cache); 194 } 195 } 196 197 /** 198 * Output the Attr[]s for the given element. 199 * <br> 200 * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a DOM which has 201 * been prepared using {@link com.sun.org.apache.xml.internal.security.utils.XMLUtils#circumventBug2650( 202 * org.w3c.dom.Document)}. 203 * 204 * @param element 205 * @param ns 206 * @param cache 207 * @throws CanonicalizationException, DOMException, IOException 208 */ 209 @Override outputAttributes(Element element, NameSpaceSymbTable ns, Map<String, byte[]> cache)210 protected void outputAttributes(Element element, NameSpaceSymbTable ns, 211 Map<String, byte[]> cache) 212 throws CanonicalizationException, DOMException, IOException { 213 // result will contain the attrs which have to be output 214 xmlattrStack.push(ns.getLevel()); 215 boolean isRealVisible = isVisibleDO(element, ns.getLevel()) == 1; 216 SortedSet<Attr> result = new TreeSet<Attr>(COMPARE); 217 218 if (element.hasAttributes()) { 219 NamedNodeMap attrs = element.getAttributes(); 220 int attrsLength = attrs.getLength(); 221 222 for (int i = 0; i < attrsLength; i++) { 223 Attr attribute = (Attr) attrs.item(i); 224 String NUri = attribute.getNamespaceURI(); 225 String NName = attribute.getLocalName(); 226 String NValue = attribute.getValue(); 227 228 if (!XMLNS_URI.equals(NUri)) { 229 //A non namespace definition node. 230 if (XML_LANG_URI.equals(NUri)) { 231 if (c14n11 && "id".equals(NName)) { 232 if (isRealVisible) { 233 // treat xml:id like any other attribute 234 // (emit it, but don't inherit it) 235 result.add(attribute); 236 } 237 } else { 238 xmlattrStack.addXmlnsAttr(attribute); 239 } 240 } else if (isRealVisible) { 241 //The node is visible add the attribute to the list of output attributes. 242 result.add(attribute); 243 } 244 } else if (!XML.equals(NName) || !XML_LANG_URI.equals(NValue)) { 245 /* except omit namespace node with local name xml, which defines 246 * the xml prefix, if its string value is http://www.w3.org/XML/1998/namespace. 247 */ 248 //add the prefix binding to the ns symb table. 249 if (isVisible(attribute)) { 250 if (isRealVisible || !ns.removeMappingIfRender(NName)) { 251 //The xpath select this node output it if needed. 252 Node n = ns.addMappingAndRender(NName, NValue, attribute); 253 if (n != null) { 254 result.add((Attr)n); 255 if (C14nHelper.namespaceIsRelative(attribute)) { 256 Object exArgs[] = { element.getTagName(), NName, attribute.getNodeValue() }; 257 throw new CanonicalizationException( 258 "c14n.Canonicalizer.RelativeNamespace", exArgs 259 ); 260 } 261 } 262 } 263 } else { 264 if (isRealVisible && !XMLNS.equals(NName)) { 265 ns.removeMapping(NName); 266 } else { 267 ns.addMapping(NName, NValue, attribute); 268 } 269 } 270 } 271 } 272 } 273 if (isRealVisible) { 274 //The element is visible, handle the xmlns definition 275 Attr xmlns = element.getAttributeNodeNS(XMLNS_URI, XMLNS); 276 Node n = null; 277 if (xmlns == null) { 278 //No xmlns def just get the already defined. 279 n = ns.getMapping(XMLNS); 280 } else if (!isVisible(xmlns)) { 281 //There is a definition but the xmlns is not selected by the xpath. 282 //then xmlns="" 283 n = ns.addMappingAndRender( 284 XMLNS, "", getNullNode(xmlns.getOwnerDocument())); 285 } 286 //output the xmlns def if needed. 287 if (n != null) { 288 result.add((Attr)n); 289 } 290 //Float all xml:* attributes of the unselected parent elements to this one. 291 xmlattrStack.getXmlnsAttr(result); 292 ns.getUnrenderedNodes(result); 293 } 294 295 OutputStream writer = getWriter(); 296 //we output all Attrs which are available 297 for (Attr attr : result) { 298 outputAttrToWriter(attr.getNodeName(), attr.getNodeValue(), writer, cache); 299 } 300 } 301 circumventBugIfNeeded(XMLSignatureInput input)302 protected void circumventBugIfNeeded(XMLSignatureInput input) 303 throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { 304 if (!input.isNeedsToBeExpanded()) { 305 return; 306 } 307 Document doc = null; 308 if (input.getSubNode() != null) { 309 doc = XMLUtils.getOwnerDocument(input.getSubNode()); 310 } else { 311 doc = XMLUtils.getOwnerDocument(input.getNodeSet()); 312 } 313 XMLUtils.circumventBug2650(doc); 314 } 315 316 @Override handleParent(Element e, NameSpaceSymbTable ns)317 protected void handleParent(Element e, NameSpaceSymbTable ns) { 318 if (!e.hasAttributes() && e.getNamespaceURI() == null) { 319 return; 320 } 321 xmlattrStack.push(-1); 322 NamedNodeMap attrs = e.getAttributes(); 323 int attrsLength = attrs.getLength(); 324 for (int i = 0; i < attrsLength; i++) { 325 Attr attribute = (Attr) attrs.item(i); 326 String NName = attribute.getLocalName(); 327 String NValue = attribute.getNodeValue(); 328 329 if (XMLNS_URI.equals(attribute.getNamespaceURI())) { 330 if (!XML.equals(NName) || !XML_LANG_URI.equals(NValue)) { 331 ns.addMapping(NName, NValue, attribute); 332 } 333 } else if (XML_LANG_URI.equals(attribute.getNamespaceURI()) 334 && (!c14n11 || !"id".equals(NName))) { 335 xmlattrStack.addXmlnsAttr(attribute); 336 } 337 } 338 if (e.getNamespaceURI() != null) { 339 String NName = e.getPrefix(); 340 String NValue = e.getNamespaceURI(); 341 String Name; 342 if (NName == null || NName.equals("")) { 343 NName = "xmlns"; 344 Name = "xmlns"; 345 } else { 346 Name = "xmlns:" + NName; 347 } 348 Attr n = e.getOwnerDocument().createAttributeNS("http://www.w3.org/2000/xmlns/", Name); 349 n.setValue(NValue); 350 ns.addMapping(NName, NValue, n); 351 } 352 } 353 } 354