Reference.java revision 11099:678faa7d1a6a
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.signature; 24 25import java.io.IOException; 26import java.io.OutputStream; 27import java.security.AccessController; 28import java.security.PrivilegedAction; 29import java.util.HashSet; 30import java.util.Iterator; 31import java.util.Set; 32 33import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm; 34import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; 35import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException; 36import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException; 37import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; 38import com.sun.org.apache.xml.internal.security.signature.reference.ReferenceData; 39import com.sun.org.apache.xml.internal.security.signature.reference.ReferenceNodeSetData; 40import com.sun.org.apache.xml.internal.security.signature.reference.ReferenceOctetStreamData; 41import com.sun.org.apache.xml.internal.security.signature.reference.ReferenceSubTreeData; 42import com.sun.org.apache.xml.internal.security.transforms.InvalidTransformException; 43import com.sun.org.apache.xml.internal.security.transforms.Transform; 44import com.sun.org.apache.xml.internal.security.transforms.TransformationException; 45import com.sun.org.apache.xml.internal.security.transforms.Transforms; 46import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces; 47import com.sun.org.apache.xml.internal.security.utils.Base64; 48import com.sun.org.apache.xml.internal.security.utils.Constants; 49import com.sun.org.apache.xml.internal.security.utils.DigesterOutputStream; 50import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; 51import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream; 52import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 53import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver; 54import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException; 55import org.w3c.dom.Attr; 56import org.w3c.dom.Document; 57import org.w3c.dom.Element; 58import org.w3c.dom.Node; 59import org.w3c.dom.Text; 60 61/** 62 * Handles <code><ds:Reference></code> elements. 63 * 64 * This includes: 65 * 66 * Constructs a <CODE>ds:Reference</CODE> from an {@link org.w3c.dom.Element}. 67 * 68 * <p>Create a new reference</p> 69 * <pre> 70 * Document doc; 71 * MessageDigestAlgorithm sha1 = MessageDigestAlgorithm.getInstance("http://#sha1"); 72 * Reference ref = new Reference(new XMLSignatureInput(new FileInputStream("1.gif"), 73 * "http://localhost/1.gif", 74 * (Transforms) null, sha1); 75 * Element refElem = ref.toElement(doc); 76 * </pre> 77 * 78 * <p>Verify a reference</p> 79 * <pre> 80 * Element refElem = doc.getElement("Reference"); // PSEUDO 81 * Reference ref = new Reference(refElem); 82 * String url = ref.getURI(); 83 * ref.setData(new XMLSignatureInput(new FileInputStream(url))); 84 * if (ref.verify()) { 85 * System.out.println("verified"); 86 * } 87 * </pre> 88 * 89 * <pre> 90 * <element name="Reference" type="ds:ReferenceType"/> 91 * <complexType name="ReferenceType"> 92 * <sequence> 93 * <element ref="ds:Transforms" minOccurs="0"/> 94 * <element ref="ds:DigestMethod"/> 95 * <element ref="ds:DigestValue"/> 96 * </sequence> 97 * <attribute name="Id" type="ID" use="optional"/> 98 * <attribute name="URI" type="anyURI" use="optional"/> 99 * <attribute name="Type" type="anyURI" use="optional"/> 100 * </complexType> 101 * </pre> 102 * 103 * @author Christian Geuer-Pollmann 104 * @see ObjectContainer 105 * @see Manifest 106 */ 107public class Reference extends SignatureElementProxy { 108 109 /** Field OBJECT_URI */ 110 public static final String OBJECT_URI = Constants.SignatureSpecNS + Constants._TAG_OBJECT; 111 112 /** Field MANIFEST_URI */ 113 public static final String MANIFEST_URI = Constants.SignatureSpecNS + Constants._TAG_MANIFEST; 114 115 /** 116 * The maximum number of transforms per reference, if secure validation is enabled. 117 */ 118 public static final int MAXIMUM_TRANSFORM_COUNT = 5; 119 120 private boolean secureValidation; 121 122 /** 123 * Look up useC14N11 system property. If true, an explicit C14N11 transform 124 * will be added if necessary when generating the signature. See section 125 * 3.1.1 of http://www.w3.org/2007/xmlsec/Drafts/xmldsig-core/ for more info. 126 */ 127 private static boolean useC14N11 = ( 128 AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 129 public Boolean run() { 130 return Boolean.valueOf(Boolean.getBoolean("com.sun.org.apache.xml.internal.security.useC14N11")); 131 } 132 })).booleanValue(); 133 134 /** {@link org.apache.commons.logging} logging facility */ 135 private static final java.util.logging.Logger log = 136 java.util.logging.Logger.getLogger(Reference.class.getName()); 137 138 private Manifest manifest; 139 private XMLSignatureInput transformsOutput; 140 141 private Transforms transforms; 142 143 private Element digestMethodElem; 144 145 private Element digestValueElement; 146 147 private ReferenceData referenceData; 148 149 /** 150 * Constructor Reference 151 * 152 * @param doc the {@link Document} in which <code>XMLsignature</code> is placed 153 * @param baseURI the URI of the resource where the XML instance will be stored 154 * @param referenceURI URI indicate where is data which will digested 155 * @param manifest 156 * @param transforms {@link Transforms} applied to data 157 * @param messageDigestAlgorithm {@link MessageDigestAlgorithm Digest algorithm} which is 158 * applied to the data 159 * TODO should we throw XMLSignatureException if MessageDigestAlgoURI is wrong? 160 * @throws XMLSignatureException 161 */ 162 protected Reference( 163 Document doc, String baseURI, String referenceURI, Manifest manifest, 164 Transforms transforms, String messageDigestAlgorithm 165 ) throws XMLSignatureException { 166 super(doc); 167 168 XMLUtils.addReturnToElement(this.constructionElement); 169 170 this.baseURI = baseURI; 171 this.manifest = manifest; 172 173 this.setURI(referenceURI); 174 175 // important: The ds:Reference must be added to the associated ds:Manifest 176 // or ds:SignedInfo _before_ the this.resolverResult() is called. 177 // this.manifest.appendChild(this.constructionElement); 178 // this.manifest.appendChild(this.doc.createTextNode("\n")); 179 180 if (transforms != null) { 181 this.transforms=transforms; 182 this.constructionElement.appendChild(transforms.getElement()); 183 XMLUtils.addReturnToElement(this.constructionElement); 184 } 185 MessageDigestAlgorithm mda = 186 MessageDigestAlgorithm.getInstance(this.doc, messageDigestAlgorithm); 187 188 digestMethodElem = mda.getElement(); 189 this.constructionElement.appendChild(digestMethodElem); 190 XMLUtils.addReturnToElement(this.constructionElement); 191 192 digestValueElement = 193 XMLUtils.createElementInSignatureSpace(this.doc, Constants._TAG_DIGESTVALUE); 194 195 this.constructionElement.appendChild(digestValueElement); 196 XMLUtils.addReturnToElement(this.constructionElement); 197 } 198 199 200 /** 201 * Build a {@link Reference} from an {@link Element} 202 * 203 * @param element <code>Reference</code> element 204 * @param baseURI the URI of the resource where the XML instance was stored 205 * @param manifest is the {@link Manifest} of {@link SignedInfo} in which the Reference occurs. 206 * We need this because the Manifest has the individual {@link ResourceResolver}s which have 207 * been set by the user 208 * @throws XMLSecurityException 209 */ 210 protected Reference(Element element, String baseURI, Manifest manifest) throws XMLSecurityException { 211 this(element, baseURI, manifest, false); 212 } 213 214 /** 215 * Build a {@link Reference} from an {@link Element} 216 * 217 * @param element <code>Reference</code> element 218 * @param baseURI the URI of the resource where the XML instance was stored 219 * @param manifest is the {@link Manifest} of {@link SignedInfo} in which the Reference occurs. 220 * @param secureValidation whether secure validation is enabled or not 221 * We need this because the Manifest has the individual {@link ResourceResolver}s which have 222 * been set by the user 223 * @throws XMLSecurityException 224 */ 225 protected Reference(Element element, String baseURI, Manifest manifest, boolean secureValidation) 226 throws XMLSecurityException { 227 super(element, baseURI); 228 this.secureValidation = secureValidation; 229 this.baseURI = baseURI; 230 Element el = XMLUtils.getNextElement(element.getFirstChild()); 231 if (Constants._TAG_TRANSFORMS.equals(el.getLocalName()) 232 && Constants.SignatureSpecNS.equals(el.getNamespaceURI())) { 233 transforms = new Transforms(el, this.baseURI); 234 transforms.setSecureValidation(secureValidation); 235 if (secureValidation && transforms.getLength() > MAXIMUM_TRANSFORM_COUNT) { 236 Object exArgs[] = { transforms.getLength(), MAXIMUM_TRANSFORM_COUNT }; 237 238 throw new XMLSecurityException("signature.tooManyTransforms", exArgs); 239 } 240 el = XMLUtils.getNextElement(el.getNextSibling()); 241 } 242 digestMethodElem = el; 243 digestValueElement = XMLUtils.getNextElement(digestMethodElem.getNextSibling()); 244 this.manifest = manifest; 245 } 246 247 /** 248 * Returns {@link MessageDigestAlgorithm} 249 * 250 * 251 * @return {@link MessageDigestAlgorithm} 252 * 253 * @throws XMLSignatureException 254 */ 255 public MessageDigestAlgorithm getMessageDigestAlgorithm() throws XMLSignatureException { 256 if (digestMethodElem == null) { 257 return null; 258 } 259 260 String uri = digestMethodElem.getAttributeNS(null, Constants._ATT_ALGORITHM); 261 262 if (uri == null) { 263 return null; 264 } 265 266 if (secureValidation && MessageDigestAlgorithm.ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5.equals(uri)) { 267 Object exArgs[] = { uri }; 268 269 throw new XMLSignatureException("signature.signatureAlgorithm", exArgs); 270 } 271 272 return MessageDigestAlgorithm.getInstance(this.doc, uri); 273 } 274 275 /** 276 * Sets the <code>URI</code> of this <code>Reference</code> element 277 * 278 * @param uri the <code>URI</code> of this <code>Reference</code> element 279 */ 280 public void setURI(String uri) { 281 if (uri != null) { 282 this.constructionElement.setAttributeNS(null, Constants._ATT_URI, uri); 283 } 284 } 285 286 /** 287 * Returns the <code>URI</code> of this <code>Reference</code> element 288 * 289 * @return URI the <code>URI</code> of this <code>Reference</code> element 290 */ 291 public String getURI() { 292 return this.constructionElement.getAttributeNS(null, Constants._ATT_URI); 293 } 294 295 /** 296 * Sets the <code>Id</code> attribute of this <code>Reference</code> element 297 * 298 * @param id the <code>Id</code> attribute of this <code>Reference</code> element 299 */ 300 public void setId(String id) { 301 if (id != null) { 302 this.constructionElement.setAttributeNS(null, Constants._ATT_ID, id); 303 this.constructionElement.setIdAttributeNS(null, Constants._ATT_ID, true); 304 } 305 } 306 307 /** 308 * Returns the <code>Id</code> attribute of this <code>Reference</code> element 309 * 310 * @return Id the <code>Id</code> attribute of this <code>Reference</code> element 311 */ 312 public String getId() { 313 return this.constructionElement.getAttributeNS(null, Constants._ATT_ID); 314 } 315 316 /** 317 * Sets the <code>type</code> atttibute of the Reference indicate whether an 318 * <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> 319 * element. 320 * 321 * @param type the <code>type</code> attribute of the Reference 322 */ 323 public void setType(String type) { 324 if (type != null) { 325 this.constructionElement.setAttributeNS(null, Constants._ATT_TYPE, type); 326 } 327 } 328 329 /** 330 * Return the <code>type</code> atttibute of the Reference indicate whether an 331 * <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> 332 * element 333 * 334 * @return the <code>type</code> attribute of the Reference 335 */ 336 public String getType() { 337 return this.constructionElement.getAttributeNS(null, Constants._ATT_TYPE); 338 } 339 340 /** 341 * Method isReferenceToObject 342 * 343 * This returns true if the <CODE>Type</CODE> attribute of the 344 * <CODE>Reference</CODE> element points to a <CODE>#Object</CODE> element 345 * 346 * @return true if the Reference type indicates that this Reference points to an 347 * <code>Object</code> 348 */ 349 public boolean typeIsReferenceToObject() { 350 if (Reference.OBJECT_URI.equals(this.getType())) { 351 return true; 352 } 353 354 return false; 355 } 356 357 /** 358 * Method isReferenceToManifest 359 * 360 * This returns true if the <CODE>Type</CODE> attribute of the 361 * <CODE>Reference</CODE> element points to a <CODE>#Manifest</CODE> element 362 * 363 * @return true if the Reference type indicates that this Reference points to a 364 * {@link Manifest} 365 */ 366 public boolean typeIsReferenceToManifest() { 367 if (Reference.MANIFEST_URI.equals(this.getType())) { 368 return true; 369 } 370 371 return false; 372 } 373 374 /** 375 * Method setDigestValueElement 376 * 377 * @param digestValue 378 */ 379 private void setDigestValueElement(byte[] digestValue) { 380 Node n = digestValueElement.getFirstChild(); 381 while (n != null) { 382 digestValueElement.removeChild(n); 383 n = n.getNextSibling(); 384 } 385 386 String base64codedValue = Base64.encode(digestValue); 387 Text t = this.doc.createTextNode(base64codedValue); 388 389 digestValueElement.appendChild(t); 390 } 391 392 /** 393 * Method generateDigestValue 394 * 395 * @throws ReferenceNotInitializedException 396 * @throws XMLSignatureException 397 */ 398 public void generateDigestValue() 399 throws XMLSignatureException, ReferenceNotInitializedException { 400 this.setDigestValueElement(this.calculateDigest(false)); 401 } 402 403 /** 404 * Returns the XMLSignatureInput which is created by de-referencing the URI attribute. 405 * @return the XMLSignatureInput of the source of this reference 406 * @throws ReferenceNotInitializedException If the resolver found any 407 * problem resolving the reference 408 */ 409 public XMLSignatureInput getContentsBeforeTransformation() 410 throws ReferenceNotInitializedException { 411 try { 412 Attr uriAttr = 413 this.constructionElement.getAttributeNodeNS(null, Constants._ATT_URI); 414 415 ResourceResolver resolver = 416 ResourceResolver.getInstance( 417 uriAttr, this.baseURI, this.manifest.getPerManifestResolvers(), secureValidation 418 ); 419 resolver.addProperties(this.manifest.getResolverProperties()); 420 421 return resolver.resolve(uriAttr, this.baseURI, secureValidation); 422 } catch (ResourceResolverException ex) { 423 throw new ReferenceNotInitializedException("empty", ex); 424 } 425 } 426 427 private XMLSignatureInput getContentsAfterTransformation( 428 XMLSignatureInput input, OutputStream os 429 ) throws XMLSignatureException { 430 try { 431 Transforms transforms = this.getTransforms(); 432 XMLSignatureInput output = null; 433 434 if (transforms != null) { 435 output = transforms.performTransforms(input, os); 436 this.transformsOutput = output;//new XMLSignatureInput(output.getBytes()); 437 438 //this.transformsOutput.setSourceURI(output.getSourceURI()); 439 } else { 440 output = input; 441 } 442 443 return output; 444 } catch (ResourceResolverException ex) { 445 throw new XMLSignatureException("empty", ex); 446 } catch (CanonicalizationException ex) { 447 throw new XMLSignatureException("empty", ex); 448 } catch (InvalidCanonicalizerException ex) { 449 throw new XMLSignatureException("empty", ex); 450 } catch (TransformationException ex) { 451 throw new XMLSignatureException("empty", ex); 452 } catch (XMLSecurityException ex) { 453 throw new XMLSignatureException("empty", ex); 454 } 455 } 456 457 /** 458 * Returns the XMLSignatureInput which is the result of the Transforms. 459 * @return a XMLSignatureInput with all transformations applied. 460 * @throws XMLSignatureException 461 */ 462 public XMLSignatureInput getContentsAfterTransformation() 463 throws XMLSignatureException { 464 XMLSignatureInput input = this.getContentsBeforeTransformation(); 465 cacheDereferencedElement(input); 466 467 return this.getContentsAfterTransformation(input, null); 468 } 469 470 /** 471 * This method returns the XMLSignatureInput which represents the node set before 472 * some kind of canonicalization is applied for the first time. 473 * @return Gets a the node doing everything till the first c14n is needed 474 * 475 * @throws XMLSignatureException 476 */ 477 public XMLSignatureInput getNodesetBeforeFirstCanonicalization() 478 throws XMLSignatureException { 479 try { 480 XMLSignatureInput input = this.getContentsBeforeTransformation(); 481 cacheDereferencedElement(input); 482 XMLSignatureInput output = input; 483 Transforms transforms = this.getTransforms(); 484 485 if (transforms != null) { 486 doTransforms: for (int i = 0; i < transforms.getLength(); i++) { 487 Transform t = transforms.item(i); 488 String uri = t.getURI(); 489 490 if (uri.equals(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS) 491 || uri.equals(Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS) 492 || uri.equals(Transforms.TRANSFORM_C14N_OMIT_COMMENTS) 493 || uri.equals(Transforms.TRANSFORM_C14N_WITH_COMMENTS)) { 494 break doTransforms; 495 } 496 497 output = t.performTransform(output, null); 498 } 499 500 output.setSourceURI(input.getSourceURI()); 501 } 502 return output; 503 } catch (IOException ex) { 504 throw new XMLSignatureException("empty", ex); 505 } catch (ResourceResolverException ex) { 506 throw new XMLSignatureException("empty", ex); 507 } catch (CanonicalizationException ex) { 508 throw new XMLSignatureException("empty", ex); 509 } catch (InvalidCanonicalizerException ex) { 510 throw new XMLSignatureException("empty", ex); 511 } catch (TransformationException ex) { 512 throw new XMLSignatureException("empty", ex); 513 } catch (XMLSecurityException ex) { 514 throw new XMLSignatureException("empty", ex); 515 } 516 } 517 518 /** 519 * Method getHTMLRepresentation 520 * @return The HTML of the transformation 521 * @throws XMLSignatureException 522 */ 523 public String getHTMLRepresentation() throws XMLSignatureException { 524 try { 525 XMLSignatureInput nodes = this.getNodesetBeforeFirstCanonicalization(); 526 527 Transforms transforms = this.getTransforms(); 528 Transform c14nTransform = null; 529 530 if (transforms != null) { 531 doTransforms: for (int i = 0; i < transforms.getLength(); i++) { 532 Transform t = transforms.item(i); 533 String uri = t.getURI(); 534 535 if (uri.equals(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS) 536 || uri.equals(Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS)) { 537 c14nTransform = t; 538 break doTransforms; 539 } 540 } 541 } 542 543 Set<String> inclusiveNamespaces = new HashSet<String>(); 544 if (c14nTransform != null 545 && (c14nTransform.length( 546 InclusiveNamespaces.ExclusiveCanonicalizationNamespace, 547 InclusiveNamespaces._TAG_EC_INCLUSIVENAMESPACES) == 1)) { 548 549 // there is one InclusiveNamespaces element 550 InclusiveNamespaces in = 551 new InclusiveNamespaces( 552 XMLUtils.selectNode( 553 c14nTransform.getElement().getFirstChild(), 554 InclusiveNamespaces.ExclusiveCanonicalizationNamespace, 555 InclusiveNamespaces._TAG_EC_INCLUSIVENAMESPACES, 556 0 557 ), this.getBaseURI()); 558 559 inclusiveNamespaces = 560 InclusiveNamespaces.prefixStr2Set(in.getInclusiveNamespaces()); 561 } 562 563 return nodes.getHTMLRepresentation(inclusiveNamespaces); 564 } catch (TransformationException ex) { 565 throw new XMLSignatureException("empty", ex); 566 } catch (InvalidTransformException ex) { 567 throw new XMLSignatureException("empty", ex); 568 } catch (XMLSecurityException ex) { 569 throw new XMLSignatureException("empty", ex); 570 } 571 } 572 573 /** 574 * This method only works after a call to verify. 575 * @return the transformed output(i.e. what is going to be digested). 576 */ 577 public XMLSignatureInput getTransformsOutput() { 578 return this.transformsOutput; 579 } 580 581 /** 582 * Get the ReferenceData that corresponds to the cached representation of the dereferenced 583 * object before transformation. 584 */ 585 public ReferenceData getReferenceData() { 586 return referenceData; 587 } 588 589 /** 590 * This method returns the {@link XMLSignatureInput} which is referenced by the 591 * <CODE>URI</CODE> Attribute. 592 * @param os where to write the transformation can be null. 593 * @return the element to digest 594 * 595 * @throws XMLSignatureException 596 * @see Manifest#verifyReferences() 597 */ 598 protected XMLSignatureInput dereferenceURIandPerformTransforms(OutputStream os) 599 throws XMLSignatureException { 600 try { 601 XMLSignatureInput input = this.getContentsBeforeTransformation(); 602 cacheDereferencedElement(input); 603 604 XMLSignatureInput output = this.getContentsAfterTransformation(input, os); 605 this.transformsOutput = output; 606 return output; 607 } catch (XMLSecurityException ex) { 608 throw new ReferenceNotInitializedException("empty", ex); 609 } 610 } 611 612 /** 613 * Store the dereferenced Element(s) so that it/they can be retrieved later. 614 */ 615 private void cacheDereferencedElement(XMLSignatureInput input) { 616 if (input.isNodeSet()) { 617 try { 618 final Set<Node> s = input.getNodeSet(); 619 referenceData = new ReferenceNodeSetData() { 620 public Iterator<Node> iterator() { 621 return new Iterator<Node>() { 622 623 Iterator<Node> sIterator = s.iterator(); 624 625 public boolean hasNext() { 626 return sIterator.hasNext(); 627 } 628 629 public Node next() { 630 return sIterator.next(); 631 } 632 633 public void remove() { 634 throw new UnsupportedOperationException(); 635 } 636 }; 637 } 638 }; 639 } catch (Exception e) { 640 // log a warning 641 log.log(java.util.logging.Level.WARNING, "cannot cache dereferenced data: " + e); 642 } 643 } else if (input.isElement()) { 644 referenceData = new ReferenceSubTreeData 645 (input.getSubNode(), input.isExcludeComments()); 646 } else if (input.isOctetStream() || input.isByteArray()) { 647 try { 648 referenceData = new ReferenceOctetStreamData 649 (input.getOctetStream(), input.getSourceURI(), 650 input.getMIMEType()); 651 } catch (IOException ioe) { 652 // log a warning 653 log.log(java.util.logging.Level.WARNING, "cannot cache dereferenced data: " + ioe); 654 } 655 } 656 } 657 658 /** 659 * Method getTransforms 660 * 661 * @return The transforms that applied this reference. 662 * @throws InvalidTransformException 663 * @throws TransformationException 664 * @throws XMLSecurityException 665 * @throws XMLSignatureException 666 */ 667 public Transforms getTransforms() 668 throws XMLSignatureException, InvalidTransformException, 669 TransformationException, XMLSecurityException { 670 return transforms; 671 } 672 673 /** 674 * Method getReferencedBytes 675 * 676 * @return the bytes that will be used to generated digest. 677 * @throws ReferenceNotInitializedException 678 * @throws XMLSignatureException 679 */ 680 public byte[] getReferencedBytes() 681 throws ReferenceNotInitializedException, XMLSignatureException { 682 try { 683 XMLSignatureInput output = this.dereferenceURIandPerformTransforms(null); 684 return output.getBytes(); 685 } catch (IOException ex) { 686 throw new ReferenceNotInitializedException("empty", ex); 687 } catch (CanonicalizationException ex) { 688 throw new ReferenceNotInitializedException("empty", ex); 689 } 690 } 691 692 693 /** 694 * Method calculateDigest 695 * 696 * @param validating true if validating the reference 697 * @return reference Calculate the digest of this reference. 698 * @throws ReferenceNotInitializedException 699 * @throws XMLSignatureException 700 */ 701 private byte[] calculateDigest(boolean validating) 702 throws ReferenceNotInitializedException, XMLSignatureException { 703 OutputStream os = null; 704 try { 705 MessageDigestAlgorithm mda = this.getMessageDigestAlgorithm(); 706 707 mda.reset(); 708 DigesterOutputStream diOs = new DigesterOutputStream(mda); 709 os = new UnsyncBufferedOutputStream(diOs); 710 XMLSignatureInput output = this.dereferenceURIandPerformTransforms(os); 711 // if signing and c14n11 property == true explicitly add 712 // C14N11 transform if needed 713 if (Reference.useC14N11 && !validating && !output.isOutputStreamSet() 714 && !output.isOctetStream()) { 715 if (transforms == null) { 716 transforms = new Transforms(this.doc); 717 transforms.setSecureValidation(secureValidation); 718 this.constructionElement.insertBefore(transforms.getElement(), digestMethodElem); 719 } 720 transforms.addTransform(Transforms.TRANSFORM_C14N11_OMIT_COMMENTS); 721 output.updateOutputStream(os, true); 722 } else { 723 output.updateOutputStream(os); 724 } 725 os.flush(); 726 727 if (output.getOctetStreamReal() != null) { 728 output.getOctetStreamReal().close(); 729 } 730 731 //this.getReferencedBytes(diOs); 732 //mda.update(data); 733 734 return diOs.getDigestValue(); 735 } catch (XMLSecurityException ex) { 736 throw new ReferenceNotInitializedException("empty", ex); 737 } catch (IOException ex) { 738 throw new ReferenceNotInitializedException("empty", ex); 739 } finally { 740 if (os != null) { 741 try { 742 os.close(); 743 } catch (IOException ex) { 744 throw new ReferenceNotInitializedException("empty", ex); 745 } 746 } 747 } 748 } 749 750 /** 751 * Returns the digest value. 752 * 753 * @return the digest value. 754 * @throws Base64DecodingException if Reference contains no proper base64 encoded data. 755 * @throws XMLSecurityException if the Reference does not contain a DigestValue element 756 */ 757 public byte[] getDigestValue() throws Base64DecodingException, XMLSecurityException { 758 if (digestValueElement == null) { 759 // The required element is not in the XML! 760 Object[] exArgs ={ Constants._TAG_DIGESTVALUE, Constants.SignatureSpecNS }; 761 throw new XMLSecurityException( 762 "signature.Verification.NoSignatureElement", exArgs 763 ); 764 } 765 return Base64.decode(digestValueElement); 766 } 767 768 769 /** 770 * Tests reference validation is success or false 771 * 772 * @return true if reference validation is success, otherwise false 773 * @throws ReferenceNotInitializedException 774 * @throws XMLSecurityException 775 */ 776 public boolean verify() 777 throws ReferenceNotInitializedException, XMLSecurityException { 778 byte[] elemDig = this.getDigestValue(); 779 byte[] calcDig = this.calculateDigest(true); 780 boolean equal = MessageDigestAlgorithm.isEqual(elemDig, calcDig); 781 782 if (!equal) { 783 log.log(java.util.logging.Level.WARNING, "Verification failed for URI \"" + this.getURI() + "\""); 784 log.log(java.util.logging.Level.WARNING, "Expected Digest: " + Base64.encode(elemDig)); 785 log.log(java.util.logging.Level.WARNING, "Actual Digest: " + Base64.encode(calcDig)); 786 } else { 787 if (log.isLoggable(java.util.logging.Level.FINE)) { 788 log.log(java.util.logging.Level.FINE, "Verification successful for URI \"" + this.getURI() + "\""); 789 } 790 } 791 792 return equal; 793 } 794 795 /** 796 * Method getBaseLocalName 797 * @inheritDoc 798 */ 799 public String getBaseLocalName() { 800 return Constants._TAG_REFERENCE; 801 } 802} 803