1 17 package com.sun.org.apache.xml.internal.security.c14n.implementations; 18 19 20 21 import java.io.ByteArrayOutputStream ; 22 import java.io.IOException ; 23 import java.io.OutputStream ; 24 import java.io.UnsupportedEncodingException ; 25 import java.util.ArrayList ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.ListIterator ; 29 import java.util.Set ; 30 31 import javax.xml.parsers.DocumentBuilderFactory ; 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.CanonicalizerSpi; 36 import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare; 37 import com.sun.org.apache.xml.internal.security.signature.NodeFilter; 38 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; 39 import com.sun.org.apache.xml.internal.security.utils.Constants; 40 import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStream; 41 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 42 import org.w3c.dom.Attr ; 43 import org.w3c.dom.Comment ; 44 import org.w3c.dom.Document ; 45 import org.w3c.dom.Element ; 46 import org.w3c.dom.NamedNodeMap ; 47 import org.w3c.dom.Node ; 48 import org.w3c.dom.ProcessingInstruction ; 49 import org.xml.sax.SAXException ; 50 51 52 58 public abstract class CanonicalizerBase extends CanonicalizerSpi { 59 private static final byte[] _END_PI = {'?','>'}; 62 private static final byte[] _BEGIN_PI = {'<','?'}; 63 private static final byte[] _END_COMM = {'-','-','>'}; 64 private static final byte[] _BEGIN_COMM = {'<','!','-','-'}; 65 private static final byte[] __XA_ = {'&','#','x','A',';'}; 66 private static final byte[] __X9_ = {'&','#','x','9',';'}; 67 private static final byte[] _QUOT_ = {'&','q','u','o','t',';'}; 68 private static final byte[] __XD_ = {'&','#','x','D',';'}; 69 private static final byte[] _GT_ = {'&','g','t',';'}; 70 private static final byte[] _LT_ = {'&','l','t',';'}; 71 private static final byte[] _END_TAG = {'<','/'}; 72 private static final byte[] _AMP_ = {'&','a','m','p',';'}; 73 final static AttrCompare COMPARE=new AttrCompare(); 74 final static String XML="xml"; 75 final static String XMLNS="xmlns"; 76 final static byte[] equalsStr= {'=','\"'}; 77 static final int NODE_BEFORE_DOCUMENT_ELEMENT = -1; 78 static final int NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT = 0; 79 static final int NODE_AFTER_DOCUMENT_ELEMENT = 1; 80 protected static final Attr nullNode; 82 static { 83 try { 84 nullNode=DocumentBuilderFactory.newInstance(). 85 newDocumentBuilder().newDocument().createAttributeNS(Constants.NamespaceSpecNS,XMLNS); 86 nullNode.setValue(""); 87 } catch (Exception e) { 88 throw new RuntimeException ("Unable to create nullNode"+e); 89 } 90 } 91 92 List nodeFilter; 93 94 boolean _includeComments; 95 Set _xpathNodeSet = null; 96 100 Node _excludeNode =null; 101 OutputStream _writer = new UnsyncByteArrayOutputStream(); 103 108 public CanonicalizerBase(boolean includeComments) { 109 this._includeComments = includeComments; 110 } 111 112 118 public byte[] engineCanonicalizeSubTree(Node rootNode) 119 throws CanonicalizationException { 120 return engineCanonicalizeSubTree(rootNode,(Node )null); 121 } 122 128 public byte[] engineCanonicalize(XMLSignatureInput input) 129 throws CanonicalizationException { 130 try { 131 if (input.isExcludeComments()) 132 _includeComments = false; 133 byte[] bytes; 134 if (input.isOctetStream()) { 135 return engineCanonicalize(input.getBytes()); 136 } 137 if (input.isElement()) { 138 bytes = engineCanonicalizeSubTree(input.getSubNode(), input 139 .getExcludeNode()); 140 return bytes; 141 } else if (input.isNodeSet()) { 142 nodeFilter=input.getNodeFilters(); 143 Document doc = null; 144 if (input.getSubNode() != null) { 145 doc=XMLUtils.getOwnerDocument(input.getSubNode()); 146 } else { 147 doc=XMLUtils.getOwnerDocument(input.getNodeSet()); 148 } 149 if (input.isNeedsToBeExpanded()) { 150 XMLUtils.circumventBug2650(doc); 151 } 152 153 if (input.getSubNode() != null) { 154 bytes = engineCanonicalizeXPathNodeSetInternal(input.getSubNode()); 155 } else { 156 bytes = engineCanonicalizeXPathNodeSet(input.getNodeSet()); 157 } 158 return bytes; 159 160 } 161 return null; 162 } catch (CanonicalizationException ex) { 163 throw new CanonicalizationException("empty", ex); 164 } catch (ParserConfigurationException ex) { 165 throw new CanonicalizationException("empty", ex); 166 } catch (IOException ex) { 167 throw new CanonicalizationException("empty", ex); 168 } catch (SAXException ex) { 169 throw new CanonicalizationException("empty", ex); 170 } 171 } 172 182 byte[] engineCanonicalizeSubTree(Node rootNode,Node excludeNode) 183 throws CanonicalizationException { 184 this._excludeNode = excludeNode; 185 try { 186 NameSpaceSymbTable ns=new NameSpaceSymbTable(); 187 if (rootNode instanceof Element ) { 188 getParentNameSpaces((Element )rootNode,ns); 190 } 191 this.canonicalizeSubTree(rootNode,ns,rootNode); 192 this._writer.close(); 193 if (this._writer instanceof ByteArrayOutputStream ) { 194 byte []result=((ByteArrayOutputStream )this._writer).toByteArray(); 195 if (reset) { 196 ((ByteArrayOutputStream )this._writer).reset(); 197 } 198 return result; 199 } 200 return null; 201 202 } catch (UnsupportedEncodingException ex) { 203 throw new CanonicalizationException("empty", ex); 204 } catch (IOException ex) { 205 throw new CanonicalizationException("empty", ex); 206 } 207 } 208 209 210 219 final void canonicalizeSubTree(Node currentNode, NameSpaceSymbTable ns,Node endnode) 220 throws CanonicalizationException, IOException { 221 Node sibling=null; 222 Node parentNode=null; 223 final OutputStream writer=this._writer; 224 final Node excludeNode=this._excludeNode; 225 final boolean includeComments=this._includeComments; 226 do { 227 switch (currentNode.getNodeType()) { 228 229 case Node.DOCUMENT_TYPE_NODE : 230 default : 231 break; 232 233 case Node.ENTITY_NODE : 234 case Node.NOTATION_NODE : 235 case Node.ATTRIBUTE_NODE : 236 throw new CanonicalizationException("empty"); 238 239 case Node.DOCUMENT_FRAGMENT_NODE : 240 case Node.DOCUMENT_NODE : 241 ns.outputNodePush(); 242 sibling= currentNode.getFirstChild(); 244 break; 245 246 case Node.COMMENT_NODE : 247 if (includeComments) { 248 outputCommentToWriter((Comment ) currentNode, writer); 249 } 250 break; 251 252 case Node.PROCESSING_INSTRUCTION_NODE : 253 outputPItoWriter((ProcessingInstruction ) currentNode, writer); 254 break; 255 256 case Node.TEXT_NODE : 257 case Node.CDATA_SECTION_NODE : 258 outputTextToWriter(currentNode.getNodeValue(), writer); 259 break; 260 261 case Node.ELEMENT_NODE : 262 if (currentNode==excludeNode) { 263 break; 264 } 265 Element currentElement = (Element ) currentNode; 266 ns.outputNodePush(); 268 writer.write('<'); 269 String name=currentElement.getTagName(); 270 writeStringToUtf8(name,writer); 271 272 Iterator attrs = this.handleAttributesSubtree(currentElement,ns); 273 if (attrs!=null) { 274 while (attrs.hasNext()) { 276 Attr attr = (Attr ) attrs.next(); 277 outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); 278 } 279 } 280 writer.write('>'); 281 sibling= currentNode.getFirstChild(); 282 if (sibling==null) { 283 writer.write(_END_TAG); 284 writeStringToUtf8(name,writer); 285 writer.write('>'); 286 ns.outputNodePop(); 288 if (parentNode != null) { 289 sibling= currentNode.getNextSibling(); 290 } 291 } else { 292 parentNode=currentElement; 293 } 294 break; 295 } 296 while (sibling==null && parentNode!=null) { 297 writer.write(_END_TAG); 298 writeStringToUtf8(((Element )parentNode).getTagName(),writer); 299 writer.write('>'); 300 ns.outputNodePop(); 302 if (parentNode==endnode) 303 return; 304 sibling=parentNode.getNextSibling(); 305 parentNode=parentNode.getParentNode(); 306 if (!(parentNode instanceof Element )) { 307 parentNode=null; 308 } 309 } 310 if (sibling==null) 311 return; 312 currentNode=sibling; 313 sibling=currentNode.getNextSibling(); 314 } while(true); 315 } 316 317 327 final static int getPositionRelativeToDocumentElement(Node currentNode) { 328 329 if ((currentNode == null) || 330 (currentNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE) ) { 331 return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; 332 } 333 Element documentElement = currentNode.getOwnerDocument().getDocumentElement(); 334 if ( (documentElement == null) || (documentElement == currentNode) ){ 335 return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; 336 } 337 338 for (Node x = currentNode; x != null; x = x.getNextSibling()) { 339 if (x == documentElement) { 340 return CanonicalizerBase.NODE_BEFORE_DOCUMENT_ELEMENT; 341 } 342 } 343 344 return CanonicalizerBase.NODE_AFTER_DOCUMENT_ELEMENT; 345 } 346 347 353 public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet) 354 throws CanonicalizationException { 355 this._xpathNodeSet = xpathNodeSet; 356 return engineCanonicalizeXPathNodeSetInternal(XMLUtils.getOwnerDocument(this._xpathNodeSet)); 357 } 358 private byte[] engineCanonicalizeXPathNodeSetInternal(Node doc) 359 throws CanonicalizationException { 360 361 try { 362 this.canonicalizeXPathNodeSet(doc,doc); 363 this._writer.close(); 364 if (this._writer instanceof ByteArrayOutputStream ) { 365 byte [] sol=((ByteArrayOutputStream )this._writer).toByteArray(); 366 if (reset) { 367 ((ByteArrayOutputStream )this._writer).reset(); 368 } 369 return sol; 370 } 371 return null; 372 } catch (UnsupportedEncodingException ex) { 373 throw new CanonicalizationException("empty", ex); 374 } catch (IOException ex) { 375 throw new CanonicalizationException("empty", ex); 376 } 377 } 378 379 388 final void canonicalizeXPathNodeSet(Node currentNode,Node endnode ) 389 throws CanonicalizationException, IOException { 390 boolean currentNodeIsVisible = false; 391 NameSpaceSymbTable ns=new NameSpaceSymbTable(); 392 Node sibling=null; 393 Node parentNode=null; 394 OutputStream writer=this._writer; 395 do { 396 switch (currentNode.getNodeType()) { 397 398 case Node.DOCUMENT_TYPE_NODE : 399 default : 400 break; 401 402 case Node.ENTITY_NODE : 403 case Node.NOTATION_NODE : 404 case Node.ATTRIBUTE_NODE : 405 throw new CanonicalizationException("empty"); 407 408 case Node.DOCUMENT_FRAGMENT_NODE : 409 case Node.DOCUMENT_NODE : 410 ns.outputNodePush(); 411 sibling= currentNode.getFirstChild(); 413 break; 414 415 case Node.COMMENT_NODE : 416 if (this._includeComments && isVisible(currentNode)) { 417 outputCommentToWriter((Comment ) currentNode, writer); 418 } 419 break; 420 421 case Node.PROCESSING_INSTRUCTION_NODE : 422 if (isVisible(currentNode)) 423 outputPItoWriter((ProcessingInstruction ) currentNode, writer); 424 break; 425 426 case Node.TEXT_NODE : 427 case Node.CDATA_SECTION_NODE : 428 if (isVisible(currentNode)) { 429 outputTextToWriter(currentNode.getNodeValue(), writer); 430 for (Node nextSibling = currentNode.getNextSibling(); 431 (nextSibling != null) 432 && ((nextSibling.getNodeType() == Node.TEXT_NODE) 433 || (nextSibling.getNodeType() 434 == Node.CDATA_SECTION_NODE)); 435 nextSibling = nextSibling.getNextSibling()) { 436 442 outputTextToWriter(nextSibling.getNodeValue(), writer); 443 currentNode=nextSibling; 444 sibling=currentNode.getNextSibling(); 445 } 446 447 } 448 break; 449 450 case Node.ELEMENT_NODE : 451 Element currentElement = (Element ) currentNode; 452 String name=null; 454 currentNodeIsVisible=isVisible(currentNode); 455 if (currentNodeIsVisible) { 456 ns.outputNodePush(); 457 writer.write('<'); 458 name=currentElement.getTagName(); 459 writeStringToUtf8(name,writer); 460 } else { 461 ns.push(); 462 } 463 464 Iterator attrs = handleAttributes(currentElement,ns); 465 if (attrs!=null) { 466 while (attrs.hasNext()) { 468 Attr attr = (Attr ) attrs.next(); 469 outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); 470 } 471 } 472 if (currentNodeIsVisible) { 473 writer.write('>'); 474 } 475 sibling= currentNode.getFirstChild(); 476 477 if (sibling==null) { 478 if (currentNodeIsVisible) { 479 writer.write(_END_TAG); 480 writeStringToUtf8(name,writer); 481 writer.write('>'); 482 ns.outputNodePop(); 484 } else { 485 ns.pop(); 486 } 487 if (parentNode != null) { 488 sibling= currentNode.getNextSibling(); 489 } 490 } else { 491 parentNode=currentElement; 492 } 493 break; 494 } 495 while (sibling==null && parentNode!=null) { 496 if (isVisible(parentNode)) { 497 writer.write(_END_TAG); 498 writeStringToUtf8(((Element )parentNode).getTagName(),writer); 499 writer.write('>'); 500 ns.outputNodePop(); 502 } else { 503 ns.pop(); 504 } 505 if (parentNode==endnode) 506 return; 507 sibling=parentNode.getNextSibling(); 508 parentNode=parentNode.getParentNode(); 509 if (!(parentNode instanceof Element )) { 510 parentNode=null; 511 } 512 } 513 if (sibling==null) 514 return; 515 currentNode=sibling; 516 sibling=currentNode.getNextSibling(); 517 } while(true); 518 } 519 520 boolean isVisible(Node currentNode) { 521 if (nodeFilter!=null) { 522 Iterator it=nodeFilter.iterator(); 523 while (it.hasNext()) { 524 if (!((NodeFilter)it.next()).isNodeInclude(currentNode)) 525 return false; 526 } 527 } 528 if ((this._xpathNodeSet!=null) && !this._xpathNodeSet.contains(currentNode)) 529 return false; 530 return true; 531 } 532 533 538 final static void getParentNameSpaces(Element el,NameSpaceSymbTable ns) { 539 List parents=new ArrayList (); 540 Node n1=el.getParentNode(); 541 if (!(n1 instanceof Element )) { 542 return; 543 } 544 Element parent=(Element ) el.getParentNode(); 546 while (parent!=null) { 547 parents.add(parent); 548 Node n=parent.getParentNode(); 549 if (!(n instanceof Element )) { 550 break; 551 } 552 parent=(Element )n; 553 } 554 ListIterator it=parents.listIterator(parents.size()); 556 while (it.hasPrevious()) { 557 Element ele=(Element )it.previous(); 558 if (!ele.hasAttributes()) { 559 continue; 560 } 561 NamedNodeMap attrs = ele.getAttributes(); 562 int attrsLength = attrs.getLength(); 563 for (int i = 0; i < attrsLength; i++) { 564 Attr N = (Attr ) attrs.item(i); 565 if (!Constants.NamespaceSpecNS.equals(N.getNamespaceURI())) { 566 continue; 568 } 569 570 String NName=N.getLocalName(); 571 String NValue=N.getNodeValue(); 572 if (XML.equals(NName) 573 && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { 574 continue; 575 } 576 ns.addMapping(NName,NValue,N); 577 } 578 } 579 Attr nsprefix; 580 if (((nsprefix=ns.getMappingWithoutRendered("xmlns"))!=null) 581 && "".equals(nsprefix.getValue())) { 582 ns.addMappingAndRender("xmlns","",nullNode); 583 } 584 } 585 604 static final void outputAttrToWriter(final String name, final String value, final OutputStream writer) throws IOException { 605 writer.write(' '); 606 writeStringToUtf8(name,writer); 607 writer.write(equalsStr); 608 byte []toWrite; 609 final int length = value.length(); 610 for (int i=0;i < length; i++) { 611 char c = value.charAt(i); 612 613 switch (c) { 614 615 case '&' : 616 toWrite=_AMP_; 617 break; 619 620 case '<' : 621 toWrite=_LT_; 622 break; 624 625 case '"' : 626 toWrite=_QUOT_; 627 break; 629 630 case 0x09 : toWrite=__X9_; 632 break; 634 635 case 0x0A : toWrite=__XA_; 637 break; 639 640 case 0x0D : toWrite=__XD_; 642 break; 644 645 default : 646 writeCharToUtf8(c,writer); 647 continue; 649 } 650 writer.write(toWrite); 651 } 652 653 writer.write('\"'); 654 } 655 656 final static void writeCharToUtf8(final char c,final OutputStream out) throws IOException { 657 char ch; 658 if ( (c <= 0x007F)) { 659 out.write(c); 660 return; 661 } 662 int bias; 663 int write; 664 if (c > 0x07FF) { 665 ch=(char)(c>>>12); 666 write=0xE0; 667 if (ch>0) { 668 write |= ( ch & 0x0F); 669 } 670 out.write(write); 671 write=0x80; 672 bias=0x3F; 673 } else { 674 write=0xC0; 675 bias=0x1F; 676 } 677 ch=(char)(c>>>6); 678 if (ch>0) { 679 write|= (ch & bias); 680 } 681 out.write(write); 682 out.write(0x80 | ((c) & 0x3F)); 683 684 } 685 686 final static void writeStringToUtf8(final String str,final OutputStream out) throws IOException { 687 final int length=str.length(); 688 int i=0; 689 char c; 690 while (i<length) { 691 c=str.charAt(i++); 692 if ( (c <= 0x007F)) { 693 out.write(c); 694 continue; 695 } 696 char ch; 697 int bias; 698 int write; 699 if (c > 0x07FF) { 700 ch=(char)(c>>>12); 701 write=0xE0; 702 if (ch>0) { 703 write |= ( ch & 0x0F); 704 } 705 out.write(write); 706 write=0x80; 707 bias=0x3F; 708 } else { 709 write=0xC0; 710 bias=0x1F; 711 } 712 ch=(char)(c>>>6); 713 if (ch>0) { 714 write|= (ch & bias); 715 } 716 out.write(write); 717 out.write(0x80 | ((c) & 0x3F)); 718 continue; 719 720 } 721 722 } 723 730 static final void outputPItoWriter(ProcessingInstruction currentPI, OutputStream writer) throws IOException { 731 final int position = getPositionRelativeToDocumentElement(currentPI); 732 733 if (position == NODE_AFTER_DOCUMENT_ELEMENT) { 734 writer.write('\n'); 735 } 736 writer.write(_BEGIN_PI); 737 738 final String target = currentPI.getTarget(); 739 int length = target.length(); 740 741 for (int i = 0; i < length; i++) { 742 char c=target.charAt(i); 743 if (c==0x0D) { 744 writer.write(__XD_); 745 } else { 746 writeCharToUtf8(c,writer); 747 } 748 } 749 750 final String data = currentPI.getData(); 751 752 length = data.length(); 753 754 if (length > 0) { 755 writer.write(' '); 756 757 for (int i = 0; i < length; i++) { 758 char c=data.charAt(i); 759 if (c==0x0D) { 760 writer.write(__XD_); 761 } else { 762 writeCharToUtf8(c,writer); 763 } 764 } 765 } 766 767 writer.write(_END_PI); 768 if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { 769 writer.write('\n'); 770 } 771 } 772 773 780 static final void outputCommentToWriter(Comment currentComment, OutputStream writer) throws IOException { 781 final int position = getPositionRelativeToDocumentElement(currentComment); 782 if (position == NODE_AFTER_DOCUMENT_ELEMENT) { 783 writer.write('\n'); 784 } 785 writer.write(_BEGIN_COMM); 786 787 final String data = currentComment.getData(); 788 final int length = data.length(); 789 790 for (int i = 0; i < length; i++) { 791 char c=data.charAt(i); 792 if (c==0x0D) { 793 writer.write(__XD_); 794 } else { 795 writeCharToUtf8(c,writer); 796 } 797 } 798 799 writer.write(_END_COMM); 800 if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { 801 writer.write('\n'); 802 } 803 } 804 805 812 static final void outputTextToWriter(final String text, final OutputStream writer) throws IOException { 813 final int length = text.length(); 814 byte []toWrite; 815 for (int i = 0; i < length; i++) { 816 char c = text.charAt(i); 817 818 switch (c) { 819 820 case '&' : 821 toWrite=_AMP_; 822 break; 824 825 case '<' : 826 toWrite=_LT_; 827 break; 829 830 case '>' : 831 toWrite=_GT_; 832 break; 834 835 case 0xD : 836 toWrite=__XD_; 837 break; 839 840 default : 841 writeCharToUtf8(c,writer); 842 continue; 843 } 844 writer.write(toWrite); 845 } 846 } 847 848 856 abstract Iterator handleAttributes(Element E, NameSpaceSymbTable ns ) 857 throws CanonicalizationException; 858 859 867 abstract Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns) 868 throws CanonicalizationException; 869 870 871 872 875 public void setWriter(OutputStream _writer) { 876 this._writer = _writer; 877 } 878 879 } 880 | Popular Tags |