1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
   9  * use this file except in compliance with the License. You may obtain a copy of
  10  * the License at
  11  *
  12  * http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  16  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  17  * License for the specific language governing permissions and limitations under
  18  * the License.
  19  *
  20  */
  21 package com.sun.org.apache.xml.internal.security.c14n.implementations;
  22 
  23 import java.io.IOException;
  24 import java.util.Iterator;
  25 import java.util.Set;
  26 import java.util.SortedSet;
  27 import java.util.TreeSet;
  28 
  29 import javax.xml.parsers.ParserConfigurationException;
  30 
  31 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
  32 import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper;
  33 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
  34 import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
  35 import com.sun.org.apache.xml.internal.security.utils.Constants;
  36 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
  37 import org.w3c.dom.Attr;
  38 import org.w3c.dom.Document;
  39 import org.w3c.dom.Element;
  40 import org.w3c.dom.NamedNodeMap;
  41 import org.w3c.dom.Node;
  42 import org.xml.sax.SAXException;
  43 /**
  44  * Implements &quot; <A
  45  * HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML
  46  * Canonicalization, Version 1.0 </A>&quot; <BR />
  47  * Credits: During restructuring of the Canonicalizer framework, Ren??
  48  * Kollmorgen from Software AG submitted an implementation of ExclC14n which
  49  * fitted into the old architecture and which based heavily on my old (and slow)
  50  * implementation of "Canonical XML". A big "thank you" to Ren?? for this.
  51  * <BR />
  52  * <i>THIS </i> implementation is a complete rewrite of the algorithm.
  53  *
  54  * @author Christian Geuer-Pollmann <geuerp@apache.org>
  55  * @version $Revision: 1.5 $
  56  * @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#">
  57  *          XML Canonicalization, Version 1.0</a>
  58  */
  59 public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
  60     /**
  61       * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of
  62       * the inclusive namespaces.
  63       */
  64     TreeSet<String> _inclusiveNSSet = new TreeSet<String>();
  65     static final String XMLNS_URI=Constants.NamespaceSpecNS;
  66     final SortedSet<Attr> result = new TreeSet<Attr>(COMPARE);
  67         /**
  68          * Constructor Canonicalizer20010315Excl
  69          *
  70          * @param includeComments
  71          */
  72         public Canonicalizer20010315Excl(boolean includeComments) {
  73                 super(includeComments);
  74         }
  75 
  76         /**
  77          * Method engineCanonicalizeSubTree
  78          * @inheritDoc
  79          * @param rootNode
  80          *
  81          * @throws CanonicalizationException
  82          */
  83         public byte[] engineCanonicalizeSubTree(Node rootNode)
  84                         throws CanonicalizationException {
  85                 return this.engineCanonicalizeSubTree(rootNode, "",null);
  86         }
  87         /**
  88          * Method engineCanonicalizeSubTree
  89          *  @inheritDoc
  90          * @param rootNode
  91          * @param inclusiveNamespaces
  92          *
  93          * @throws CanonicalizationException
  94          */
  95         public byte[] engineCanonicalizeSubTree(Node rootNode,
  96                         String inclusiveNamespaces) throws CanonicalizationException {
  97                 return this.engineCanonicalizeSubTree(rootNode, inclusiveNamespaces,null);
  98         }
  99         /**
 100          * Method engineCanonicalizeSubTree
 101          * @param rootNode
 102      * @param inclusiveNamespaces
 103      * @param excl A element to exclude from the c14n process.
 104          * @return the rootNode c14n.
 105          * @throws CanonicalizationException
 106          */
 107         public byte[] engineCanonicalizeSubTree(Node rootNode,
 108                         String inclusiveNamespaces,Node excl) throws CanonicalizationException {
 109                         this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces);
 110                         return super.engineCanonicalizeSubTree(rootNode,excl);
 111         }
 112         /**
 113          *
 114          * @param rootNode
 115          * @param inclusiveNamespaces
 116          * @return the rootNode c14n.
 117          * @throws CanonicalizationException
 118          */
 119         @SuppressWarnings("unchecked")
 120         public byte[] engineCanonicalize(XMLSignatureInput rootNode,
 121                         String inclusiveNamespaces) throws CanonicalizationException {
 122                         this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces);
 123                         return super.engineCanonicalize(rootNode);
 124         }
 125 
 126         /**
 127          * Method handleAttributesSubtree
 128          * @inheritDoc
 129          * @param E
 130          * @throws CanonicalizationException
 131          */
 132         Iterator<Attr> handleAttributesSubtree(Element E,NameSpaceSymbTable ns)
 133                         throws CanonicalizationException {
 134                 // System.out.println("During the traversal, I encountered " +
 135                 // XMLUtils.getXPath(E));
 136                 // result will contain the attrs which have to be outputted
 137                 SortedSet<Attr> result = this.result;
 138             result.clear();
 139                 NamedNodeMap attrs=null;
 140 
 141                 int attrsLength = 0;
 142         if (E.hasAttributes()) {
 143             attrs = E.getAttributes();
 144                 attrsLength = attrs.getLength();
 145         }
 146                 //The prefix visibly utilized(in the attribute or in the name) in the element
 147                 SortedSet<String> visiblyUtilized = getNSSetClone();
 148 
 149                 for (int i = 0; i < attrsLength; i++) {
 150                         Attr N = (Attr) attrs.item(i);
 151 
 152                         if (XMLNS_URI!=N.getNamespaceURI()) {
 153                                 //Not a namespace definition.
 154                                 //The Element is output element, add his prefix(if used) to visibyUtilized
 155                                 String prefix = N.getPrefix();
 156                                 if ( (prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ) {
 157                                                 visiblyUtilized.add(prefix);
 158                                 }
 159                                 //Add to the result.
 160                                  result.add(N);
 161                                 continue;
 162                         }
 163                         String NName=N.getLocalName();
 164                         String NNodeValue=N.getNodeValue();
 165 
 166                         if (ns.addMapping(NName, NNodeValue,N)) {
 167                                 //New definition check if it is relative.
 168                 if (C14nHelper.namespaceIsRelative(NNodeValue)) {
 169                     Object exArgs[] = {E.getTagName(), NName,
 170                             N.getNodeValue()};
 171                     throw new CanonicalizationException(
 172                             "c14n.Canonicalizer.RelativeNamespace", exArgs);
 173                 }
 174             }
 175                 }
 176                 String prefix;
 177                 if (E.getNamespaceURI() != null) {
 178                         prefix = E.getPrefix();
 179                         if ((prefix == null) || (prefix.length() == 0)) {
 180                                 prefix=XMLNS;
 181                         }
 182 
 183                 } else {
 184                         prefix=XMLNS;
 185                 }
 186                 visiblyUtilized.add(prefix);
 187 
 188                 //This can be optimezed by I don't have time
 189                 Iterator<String> it=visiblyUtilized.iterator();
 190                 while (it.hasNext()) {
 191                         String s=it.next();
 192                         Attr key=ns.getMapping(s);
 193                         if (key==null) {
 194                                 continue;
 195                         }
 196                         result.add(key);
 197                 }
 198 
 199                 return result.iterator();
 200         }
 201 
 202         /**
 203          * Method engineCanonicalizeXPathNodeSet
 204          * @inheritDoc
 205          * @param xpathNodeSet
 206          * @param inclusiveNamespaces
 207          * @throws CanonicalizationException
 208          */
 209         public byte[] engineCanonicalizeXPathNodeSet(Set<Node> xpathNodeSet,
 210                         String inclusiveNamespaces) throws CanonicalizationException {
 211 
 212                         this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces);
 213                         return super.engineCanonicalizeXPathNodeSet(xpathNodeSet);
 214 
 215         }
 216 
 217     @SuppressWarnings("unchecked")
 218     private TreeSet<String> getInclusiveNameSpace(String inclusiveNameSpaces) {
 219         return (TreeSet<String>)InclusiveNamespaces.prefixStr2Set(inclusiveNameSpaces);
 220     }
 221 
 222 
 223     @SuppressWarnings("unchecked")
 224     private SortedSet<String> getNSSetClone() {
 225         return (SortedSet<String>) this._inclusiveNSSet.clone();
 226     }
 227 
 228 
 229         /**
 230      * @inheritDoc
 231          * @param E
 232          * @throws CanonicalizationException
 233          */
 234         final Iterator<Attr> handleAttributes(Element E, NameSpaceSymbTable ns)
 235                         throws CanonicalizationException {
 236                 // result will contain the attrs which have to be outputted
 237                 SortedSet<Attr> result = this.result;
 238             result.clear();
 239                 NamedNodeMap attrs = null;
 240                 int attrsLength = 0;
 241         if (E.hasAttributes()) {
 242             attrs = E.getAttributes();
 243                 attrsLength = attrs.getLength();
 244         }
 245                 //The prefix visibly utilized(in the attribute or in the name) in the element
 246                 Set<String> visiblyUtilized =null;
 247                 //It's the output selected.
 248                 boolean isOutputElement=isVisibleDO(E,ns.getLevel())==1;
 249                 if (isOutputElement) {
 250                         visiblyUtilized =  getNSSetClone();
 251                 }
 252 
 253                 for (int i = 0; i < attrsLength; i++) {
 254                         Attr N = (Attr) attrs.item(i);
 255 
 256 
 257                         if (XMLNS_URI!=N.getNamespaceURI()) {
 258                                 if ( !isVisible(N) )  {
 259                                         //The node is not in the nodeset(if there is a nodeset)
 260                                         continue;
 261                                 }
 262                                 //Not a namespace definition.
 263                                 if (isOutputElement) {
 264                                         //The Element is output element, add his prefix(if used) to visibyUtilized
 265                                         String prefix = N.getPrefix();
 266                                         if ((prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ){
 267                                                         visiblyUtilized.add(prefix);
 268                                         }
 269                                         //Add to the result.
 270                                     result.add(N);
 271                                 }
 272                                 continue;
 273                         }
 274                         String NName=N.getLocalName();
 275                         if (isOutputElement && !isVisible(N) && NName!=XMLNS) {
 276                         ns.removeMappingIfNotRender(NName);
 277                         continue;
 278                 }
 279                         String NNodeValue=N.getNodeValue();
 280 
 281                         if (!isOutputElement && isVisible(N) && _inclusiveNSSet.contains(NName) && !ns.removeMappingIfRender(NName)) {
 282                                 Node n=ns.addMappingAndRender(NName,NNodeValue,N);
 283                                 if (n!=null) {
 284                                                 result.add((Attr)n);
 285                             if (C14nHelper.namespaceIsRelative(N)) {
 286                                Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() };
 287                                throw new CanonicalizationException(
 288                                   "c14n.Canonicalizer.RelativeNamespace", exArgs);
 289                            }
 290                                  }
 291                         }
 292 
 293 
 294 
 295                         if (ns.addMapping(NName, NNodeValue,N)) {
 296                 //New definiton check if it is relative
 297                 if (C14nHelper.namespaceIsRelative(NNodeValue)) {
 298                     Object exArgs[] = {E.getTagName(), NName,
 299                             N.getNodeValue()};
 300                     throw new CanonicalizationException(
 301                             "c14n.Canonicalizer.RelativeNamespace", exArgs);
 302                 }
 303             }
 304                 }
 305 
 306                 if (isOutputElement) {
 307            //The element is visible, handle the xmlns definition
 308            Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
 309            if ((xmlns!=null) &&  (!isVisible(xmlns))) {
 310               //There is a definition but the xmlns is not selected by the xpath.
 311               //then xmlns=""
 312               ns.addMapping(XMLNS,"",nullNode);
 313             }
 314 
 315                         if (E.getNamespaceURI() != null) {
 316                                 String prefix = E.getPrefix();
 317                                 if ((prefix == null) || (prefix.length() == 0)) {
 318                                         visiblyUtilized.add(XMLNS);
 319                                 } else {
 320                                         visiblyUtilized.add( prefix);
 321                                 }
 322                         } else {
 323                                 visiblyUtilized.add(XMLNS);
 324                         }
 325                         //This can be optimezed by I don't have time
 326                         //visiblyUtilized.addAll(this._inclusiveNSSet);
 327                         Iterator<String> it=visiblyUtilized.iterator();
 328                         while (it.hasNext()) {
 329                                 String s=it.next();
 330                                 Attr key=ns.getMapping(s);
 331                                 if (key==null) {
 332                                         continue;
 333                                 }
 334                                 result.add(key);
 335                         }
 336                 }
 337 
 338                 return result.iterator();
 339         }
 340         void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException {
 341                 if (!input.isNeedsToBeExpanded() || _inclusiveNSSet.isEmpty())
 342                         return;
 343                 Document doc = null;
 344                if (input.getSubNode() != null) {
 345                    doc=XMLUtils.getOwnerDocument(input.getSubNode());
 346                } else {
 347                    doc=XMLUtils.getOwnerDocument(input.getNodeSet());
 348                }
 349 
 350                 XMLUtils.circumventBug2650(doc);
 351            }
 352 }