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 */ 23package com.sun.org.apache.xml.internal.security.c14n; 24 25import java.io.ByteArrayInputStream; 26import java.io.InputStream; 27import java.io.OutputStream; 28import java.util.Map; 29import java.util.Set; 30import java.util.concurrent.ConcurrentHashMap; 31 32import javax.xml.XMLConstants; 33import javax.xml.parsers.DocumentBuilder; 34import javax.xml.parsers.DocumentBuilderFactory; 35 36import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_OmitComments; 37import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_WithComments; 38import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315ExclOmitComments; 39import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315ExclWithComments; 40import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315OmitComments; 41import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315WithComments; 42import com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerPhysical; 43import com.sun.org.apache.xml.internal.security.exceptions.AlgorithmAlreadyRegisteredException; 44import com.sun.org.apache.xml.internal.security.utils.JavaUtils; 45import org.w3c.dom.Document; 46import org.w3c.dom.Node; 47import org.w3c.dom.NodeList; 48import org.xml.sax.InputSource; 49 50/** 51 * 52 * @author Christian Geuer-Pollmann 53 */ 54public class Canonicalizer { 55 56 /** The output encoding of canonicalized data */ 57 public static final String ENCODING = "UTF8"; 58 59 /** 60 * XPath Expression for selecting every node and continuous comments joined 61 * in only one node 62 */ 63 public static final String XPATH_C14N_WITH_COMMENTS_SINGLE_NODE = 64 "(.//. | .//@* | .//namespace::*)"; 65 66 /** 67 * The URL defined in XML-SEC Rec for inclusive c14n <b>without</b> comments. 68 */ 69 public static final String ALGO_ID_C14N_OMIT_COMMENTS = 70 "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; 71 /** 72 * The URL defined in XML-SEC Rec for inclusive c14n <b>with</b> comments. 73 */ 74 public static final String ALGO_ID_C14N_WITH_COMMENTS = 75 ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; 76 /** 77 * The URL defined in XML-SEC Rec for exclusive c14n <b>without</b> comments. 78 */ 79 public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = 80 "http://www.w3.org/2001/10/xml-exc-c14n#"; 81 /** 82 * The URL defined in XML-SEC Rec for exclusive c14n <b>with</b> comments. 83 */ 84 public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = 85 ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; 86 /** 87 * The URI for inclusive c14n 1.1 <b>without</b> comments. 88 */ 89 public static final String ALGO_ID_C14N11_OMIT_COMMENTS = 90 "http://www.w3.org/2006/12/xml-c14n11"; 91 /** 92 * The URI for inclusive c14n 1.1 <b>with</b> comments. 93 */ 94 public static final String ALGO_ID_C14N11_WITH_COMMENTS = 95 ALGO_ID_C14N11_OMIT_COMMENTS + "#WithComments"; 96 /** 97 * Non-standard algorithm to serialize the physical representation for XML Encryption 98 */ 99 public static final String ALGO_ID_C14N_PHYSICAL = 100 "http://santuario.apache.org/c14n/physical"; 101 102 private static Map<String, Class<? extends CanonicalizerSpi>> canonicalizerHash = 103 new ConcurrentHashMap<String, Class<? extends CanonicalizerSpi>>(); 104 105 private final CanonicalizerSpi canonicalizerSpi; 106 107 /** 108 * Constructor Canonicalizer 109 * 110 * @param algorithmURI 111 * @throws InvalidCanonicalizerException 112 */ 113 private Canonicalizer(String algorithmURI) throws InvalidCanonicalizerException { 114 try { 115 Class<? extends CanonicalizerSpi> implementingClass = 116 canonicalizerHash.get(algorithmURI); 117 118 @SuppressWarnings("deprecation") 119 CanonicalizerSpi tmp = implementingClass.newInstance(); 120 canonicalizerSpi = tmp; 121 canonicalizerSpi.reset = true; 122 } catch (Exception e) { 123 Object exArgs[] = { algorithmURI }; 124 throw new InvalidCanonicalizerException( 125 "signature.Canonicalizer.UnknownCanonicalizer", exArgs, e 126 ); 127 } 128 } 129 130 /** 131 * Method getInstance 132 * 133 * @param algorithmURI 134 * @return a Canonicalizer instance ready for the job 135 * @throws InvalidCanonicalizerException 136 */ 137 public static final Canonicalizer getInstance(String algorithmURI) 138 throws InvalidCanonicalizerException { 139 return new Canonicalizer(algorithmURI); 140 } 141 142 /** 143 * Method register 144 * 145 * @param algorithmURI 146 * @param implementingClass 147 * @throws AlgorithmAlreadyRegisteredException 148 * @throws SecurityException if a security manager is installed and the 149 * caller does not have permission to register the canonicalizer 150 */ 151 @SuppressWarnings("unchecked") 152 public static void register(String algorithmURI, String implementingClass) 153 throws AlgorithmAlreadyRegisteredException, ClassNotFoundException { 154 JavaUtils.checkRegisterPermission(); 155 // check whether URI is already registered 156 Class<? extends CanonicalizerSpi> registeredClass = 157 canonicalizerHash.get(algorithmURI); 158 159 if (registeredClass != null) { 160 Object exArgs[] = { algorithmURI, registeredClass }; 161 throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs); 162 } 163 164 canonicalizerHash.put( 165 algorithmURI, (Class<? extends CanonicalizerSpi>)Class.forName(implementingClass) 166 ); 167 } 168 169 /** 170 * Method register 171 * 172 * @param algorithmURI 173 * @param implementingClass 174 * @throws AlgorithmAlreadyRegisteredException 175 * @throws SecurityException if a security manager is installed and the 176 * caller does not have permission to register the canonicalizer 177 */ 178 public static void register(String algorithmURI, Class<? extends CanonicalizerSpi> implementingClass) 179 throws AlgorithmAlreadyRegisteredException, ClassNotFoundException { 180 JavaUtils.checkRegisterPermission(); 181 // check whether URI is already registered 182 Class<? extends CanonicalizerSpi> registeredClass = canonicalizerHash.get(algorithmURI); 183 184 if (registeredClass != null) { 185 Object exArgs[] = { algorithmURI, registeredClass }; 186 throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs); 187 } 188 189 canonicalizerHash.put(algorithmURI, implementingClass); 190 } 191 192 /** 193 * This method registers the default algorithms. 194 */ 195 public static void registerDefaultAlgorithms() { 196 canonicalizerHash.put( 197 Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS, 198 Canonicalizer20010315OmitComments.class 199 ); 200 canonicalizerHash.put( 201 Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS, 202 Canonicalizer20010315WithComments.class 203 ); 204 canonicalizerHash.put( 205 Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS, 206 Canonicalizer20010315ExclOmitComments.class 207 ); 208 canonicalizerHash.put( 209 Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS, 210 Canonicalizer20010315ExclWithComments.class 211 ); 212 canonicalizerHash.put( 213 Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS, 214 Canonicalizer11_OmitComments.class 215 ); 216 canonicalizerHash.put( 217 Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS, 218 Canonicalizer11_WithComments.class 219 ); 220 canonicalizerHash.put( 221 Canonicalizer.ALGO_ID_C14N_PHYSICAL, 222 CanonicalizerPhysical.class 223 ); 224 } 225 226 /** 227 * Method getURI 228 * 229 * @return the URI defined for this c14n instance. 230 */ 231 public final String getURI() { 232 return canonicalizerSpi.engineGetURI(); 233 } 234 235 /** 236 * Method getIncludeComments 237 * 238 * @return true if the c14n respect the comments. 239 */ 240 public boolean getIncludeComments() { 241 return canonicalizerSpi.engineGetIncludeComments(); 242 } 243 244 /** 245 * This method tries to canonicalize the given bytes. It's possible to even 246 * canonicalize non-wellformed sequences if they are well-formed after being 247 * wrapped with a <CODE>>a<...>/a<</CODE>. 248 * 249 * @param inputBytes 250 * @return the result of the canonicalization. 251 * @throws CanonicalizationException 252 * @throws java.io.IOException 253 * @throws javax.xml.parsers.ParserConfigurationException 254 * @throws org.xml.sax.SAXException 255 */ 256 public byte[] canonicalize(byte[] inputBytes) 257 throws javax.xml.parsers.ParserConfigurationException, 258 java.io.IOException, org.xml.sax.SAXException, CanonicalizationException { 259 InputStream bais = new ByteArrayInputStream(inputBytes); 260 InputSource in = new InputSource(bais); 261 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 262 dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); 263 264 dfactory.setNamespaceAware(true); 265 266 // needs to validate for ID attribute normalization 267 dfactory.setValidating(true); 268 269 DocumentBuilder db = dfactory.newDocumentBuilder(); 270 271 /* 272 * for some of the test vectors from the specification, 273 * there has to be a validating parser for ID attributes, default 274 * attribute values, NMTOKENS, etc. 275 * Unfortunately, the test vectors do use different DTDs or 276 * even no DTD. So Xerces 1.3.1 fires many warnings about using 277 * ErrorHandlers. 278 * 279 * Text from the spec: 280 * 281 * The input octet stream MUST contain a well-formed XML document, 282 * but the input need not be validated. However, the attribute 283 * value normalization and entity reference resolution MUST be 284 * performed in accordance with the behaviors of a validating 285 * XML processor. As well, nodes for default attributes (declared 286 * in the ATTLIST with an AttValue but not specified) are created 287 * in each element. Thus, the declarations in the document type 288 * declaration are used to help create the canonical form, even 289 * though the document type declaration is not retained in the 290 * canonical form. 291 */ 292 db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils.IgnoreAllErrorHandler()); 293 294 Document document = db.parse(in); 295 return this.canonicalizeSubtree(document); 296 } 297 298 /** 299 * Canonicalizes the subtree rooted by <CODE>node</CODE>. 300 * 301 * @param node The node to canonicalize 302 * @return the result of the c14n. 303 * 304 * @throws CanonicalizationException 305 */ 306 public byte[] canonicalizeSubtree(Node node) throws CanonicalizationException { 307 return canonicalizerSpi.engineCanonicalizeSubTree(node); 308 } 309 310 /** 311 * Canonicalizes the subtree rooted by <CODE>node</CODE>. 312 * 313 * @param node 314 * @param inclusiveNamespaces 315 * @return the result of the c14n. 316 * @throws CanonicalizationException 317 */ 318 public byte[] canonicalizeSubtree(Node node, String inclusiveNamespaces) 319 throws CanonicalizationException { 320 return canonicalizerSpi.engineCanonicalizeSubTree(node, inclusiveNamespaces); 321 } 322 323 /** 324 * Canonicalizes an XPath node set. The <CODE>xpathNodeSet</CODE> is treated 325 * as a list of XPath nodes, not as a list of subtrees. 326 * 327 * @param xpathNodeSet 328 * @return the result of the c14n. 329 * @throws CanonicalizationException 330 */ 331 public byte[] canonicalizeXPathNodeSet(NodeList xpathNodeSet) 332 throws CanonicalizationException { 333 return canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); 334 } 335 336 /** 337 * Canonicalizes an XPath node set. The <CODE>xpathNodeSet</CODE> is treated 338 * as a list of XPath nodes, not as a list of subtrees. 339 * 340 * @param xpathNodeSet 341 * @param inclusiveNamespaces 342 * @return the result of the c14n. 343 * @throws CanonicalizationException 344 */ 345 public byte[] canonicalizeXPathNodeSet( 346 NodeList xpathNodeSet, String inclusiveNamespaces 347 ) throws CanonicalizationException { 348 return 349 canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, inclusiveNamespaces); 350 } 351 352 /** 353 * Canonicalizes an XPath node set. 354 * 355 * @param xpathNodeSet 356 * @return the result of the c14n. 357 * @throws CanonicalizationException 358 */ 359 public byte[] canonicalizeXPathNodeSet(Set<Node> xpathNodeSet) 360 throws CanonicalizationException { 361 return canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); 362 } 363 364 /** 365 * Canonicalizes an XPath node set. 366 * 367 * @param xpathNodeSet 368 * @param inclusiveNamespaces 369 * @return the result of the c14n. 370 * @throws CanonicalizationException 371 */ 372 public byte[] canonicalizeXPathNodeSet( 373 Set<Node> xpathNodeSet, String inclusiveNamespaces 374 ) throws CanonicalizationException { 375 return 376 canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, inclusiveNamespaces); 377 } 378 379 /** 380 * Sets the writer where the canonicalization ends. ByteArrayOutputStream 381 * if none is set. 382 * @param os 383 */ 384 public void setWriter(OutputStream os) { 385 canonicalizerSpi.setWriter(os); 386 } 387 388 /** 389 * Returns the name of the implementing {@link CanonicalizerSpi} class 390 * 391 * @return the name of the implementing {@link CanonicalizerSpi} class 392 */ 393 public String getImplementingCanonicalizerClass() { 394 return canonicalizerSpi.getClass().getName(); 395 } 396 397 /** 398 * Set the canonicalizer behaviour to not reset. 399 */ 400 public void notReset() { 401 canonicalizerSpi.reset = false; 402 } 403 404} 405