src/share/classes/com/sun/org/apache/xml/internal/security/signature/Manifest.java

Print this page


   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");
   9  *  you may not use this file except in compliance with the License.
  10  *  You may obtain a copy of 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,
  16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  *  See the License for the specific language governing permissions and
  18  *  limitations under the License.
  19  *
  20  */
  21 package com.sun.org.apache.xml.internal.security.signature;
  22 
  23 
  24 
  25 import java.io.IOException;
  26 import java.util.ArrayList;
  27 import java.util.HashMap;
  28 import java.util.Iterator;
  29 import java.util.List;
  30 import java.util.Set;
  31 import java.util.Map;

  32 
  33 import javax.xml.parsers.ParserConfigurationException;
  34 
  35 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
  36 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
  37 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
  38 import com.sun.org.apache.xml.internal.security.transforms.Transforms;
  39 import com.sun.org.apache.xml.internal.security.utils.Constants;
  40 import com.sun.org.apache.xml.internal.security.utils.I18n;
  41 import com.sun.org.apache.xml.internal.security.utils.IdResolver;
  42 import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
  43 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
  44 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
  45 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
  46 import org.w3c.dom.Attr;
  47 import org.w3c.dom.DOMException;
  48 import org.w3c.dom.Document;
  49 import org.w3c.dom.Element;
  50 import org.w3c.dom.Node;
  51 import org.xml.sax.SAXException;
  52 
  53 
  54 
  55 /**
  56  * Handles <code>&lt;ds:Manifest&gt;</code> elements.
  57  * <p> This element holds the <code>Reference</code> elements</p>
  58  * @author $author: $
  59  */
  60 public class Manifest extends SignatureElementProxy {
  61 
  62   /** {@link java.util.logging} logging facility */
  63   static java.util.logging.Logger log =





  64         java.util.logging.Logger.getLogger(Manifest.class.getName());
  65 
  66    /** Field _references */
  67    List<Reference> _references;
  68    Element[] _referencesEl;
  69 
  70    /** Field verificationResults[] */
  71    private boolean verificationResults[] = null;
  72 
  73    /** Field _resolverProperties */
  74    Map<String,String> _resolverProperties = null;
  75 
  76    /** Field _perManifestResolvers */
  77    List<ResourceResolver> _perManifestResolvers = null;


  78 
  79    /**
  80     * Consturts {@link Manifest}
  81     *
  82     * @param doc the {@link Document} in which <code>XMLsignature</code> is placed
  83     */
  84    public Manifest(Document doc) {
  85 
  86       super(doc);
  87 
  88       XMLUtils.addReturnToElement(this._constructionElement);
  89 
  90       this._references = new ArrayList<Reference>();
  91    }
  92 
  93    /**
  94     * Constructor Manifest
  95     *
  96     * @param element
  97     * @param BaseURI
  98     * @throws XMLSecurityException
  99     */
 100    public Manifest(Element element, String BaseURI)
 101            throws XMLSecurityException {
 102 
 103       super(element, BaseURI);












 104 
 105       Attr attr = element.getAttributeNodeNS(null, "Id");
 106       if (attr != null) {
 107           element.setIdAttributeNode(attr, true);
 108       }

 109 
 110       // check out Reference children
 111       this._referencesEl = XMLUtils.selectDsNodes(this._constructionElement.getFirstChild(),
 112          Constants._TAG_REFERENCE);
 113       int le = this._referencesEl.length;
 114       {

 115          if (le == 0) {
 116 
 117             // At least one Reference must be present. Bad.
 118             Object exArgs[] = { Constants._TAG_REFERENCE,
 119                                 Constants._TAG_MANIFEST };
 120 
 121             throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
 122                                    I18n.translate("xml.WrongContent", exArgs));
 123          }





 124       }
 125 
 126       // create Vector
 127       this._references = new ArrayList<Reference>(le);
 128 
 129       for (int i = 0; i < le; i++) {
 130          Element refElem = this._referencesEl[i];
 131          Attr refAttr = refElem.getAttributeNodeNS(null, "Id");
 132          if (refAttr != null) {
 133              refElem.setIdAttributeNode(refAttr, true);
 134          }
 135          this._references.add(null);
 136       }
 137    }
 138 
 139    /**
 140     * This <code>addDocument</code> method is used to add a new resource to the
 141     * signed info. A {@link com.sun.org.apache.xml.internal.security.signature.Reference} is built
 142     * from the supplied values.
 143     *
 144     * @param BaseURI the URI of the resource where the XML instance was stored
 145     * @param referenceURI <code>URI</code> attribute in <code>Reference</code> for specifing where data is
 146     * @param transforms com.sun.org.apache.xml.internal.security.signature.Transforms object with an ordered list of transformations to be performed.
 147     * @param digestURI The digest algorthim URI to be used.
 148     * @param ReferenceId
 149     * @param ReferenceType


 150     * @throws XMLSignatureException
 151     */
 152    public void addDocument(
 153            String BaseURI, String referenceURI, Transforms transforms, String digestURI, String ReferenceId, String ReferenceType)
 154               throws XMLSignatureException {
 155 
 156          // the this._doc is handed implicitly by the this.getOwnerDocument()
 157          Reference ref = new Reference(this._doc, BaseURI, referenceURI, this,
 158                                        transforms, digestURI);
 159 
 160          if (ReferenceId != null) {
 161             ref.setId(ReferenceId);
 162          }
 163 
 164          if (ReferenceType != null) {
 165             ref.setType(ReferenceType);
 166          }
 167 
 168          // add Reference object to our cache vector
 169          this._references.add(ref);
 170 
 171          // add the Element of the Reference object to the Manifest/SignedInfo
 172          this._constructionElement.appendChild(ref.getElement());
 173          XMLUtils.addReturnToElement(this._constructionElement);
 174    }
 175 
 176    /**
 177     * The calculation of the DigestValues in the References must be after the
 178     * References are already added to the document and during the signing
 179     * process. This ensures that all neccesary data is in place.
 180     *
 181     * @throws ReferenceNotInitializedException
 182     * @throws XMLSignatureException
 183     */
 184    public void generateDigestValues()
 185            throws XMLSignatureException, ReferenceNotInitializedException {
 186 
 187          for (int i = 0; i < this.getLength(); i++) {
 188 
 189             // update the cached Reference object, the Element content is automatically updated
 190             Reference currentRef = this._references.get(i);
 191 
 192             currentRef.generateDigestValue();
 193          }
 194    }
 195 
 196    /**
 197     * Return the nonnegative number of added references.
 198     *
 199     * @return the number of references
 200     */
 201    public int getLength() {
 202       return this._references.size();
 203    }
 204 
 205    /**
 206     * Return the <it>i</it><sup>th</sup> reference.  Valid <code>i</code>
 207     * values are 0 to <code>{link@ getSize}-1</code>.
 208     *
 209     * @param i Index of the requested {@link Reference}
 210     * @return the <it>i</it><sup>th</sup> reference
 211     * @throws XMLSecurityException
 212     */
 213    public Reference item(int i) throws XMLSecurityException {
 214 
 215          if (this._references.get(i) == null) {
 216 
 217             // not yet constructed, so _we_ have to
 218             Reference ref = new Reference(_referencesEl[i], this._baseURI, this);

 219 
 220             this._references.set(i, ref);
 221          }
 222 
 223          return this._references.get(i);
 224 
 225    }
 226 
 227    /**
 228     * Sets the <code>Id</code> attribute
 229     *
 230     * @param Id the <code>Id</code> attribute in <code>ds:Manifest</code>
 231     */
 232    public void setId(String Id) {
 233 
 234       if (Id != null) {
 235           setLocalIdAttribute(Constants._ATT_ID, Id);

 236       }
 237    }
 238 
 239    /**
 240     * Returns the <code>Id</code> attribute
 241     *
 242     * @return the <code>Id</code> attribute in <code>ds:Manifest</code>
 243     */
 244    public String getId() {
 245       return this._constructionElement.getAttributeNS(null, Constants._ATT_ID);
 246    }
 247 
 248    /**
 249     * Used to do a <A HREF="http://www.w3.org/TR/xmldsig-core/#def-ValidationReference">reference
 250     * validation</A> of all enclosed references using the {@link Reference#verify} method.
 251     *
 252     * <p>This step loops through all {@link Reference}s and does verify the hash
 253     * values. If one or more verifications fail, the method returns
 254     * <code>false</code>. If <i>all</i> verifications are successful,
 255     * it returns <code>true</code>. The results of the individual reference
 256     * validations are available by using the {@link #getVerificationResult(int)} method
 257     *
 258     * @return true if all References verify, false if one or more do not verify.
 259     * @throws MissingResourceFailureException if a {@link Reference} does not verify (throws a {@link com.sun.org.apache.xml.internal.security.signature.ReferenceNotInitializedException} because of an uninitialized {@link XMLSignatureInput}


 260     * @see com.sun.org.apache.xml.internal.security.signature.Reference#verify
 261     * @see com.sun.org.apache.xml.internal.security.signature.SignedInfo#verify()
 262     * @see com.sun.org.apache.xml.internal.security.signature.MissingResourceFailureException
 263     * @throws XMLSecurityException
 264     */
 265    public boolean verifyReferences()
 266            throws MissingResourceFailureException, XMLSecurityException {
 267       return this.verifyReferences(false);
 268    }
 269 
 270    /**
 271     * Used to do a <A HREF="http://www.w3.org/TR/xmldsig-core/#def-ValidationReference">reference
 272     * validation</A> of all enclosed references using the {@link Reference#verify} method.
 273     *
 274     * <p>This step loops through all {@link Reference}s and does verify the hash
 275     * values. If one or more verifications fail, the method returns
 276     * <code>false</code>. If <i>all</i> verifications are successful,
 277     * it returns <code>true</code>. The results of the individual reference
 278     * validations are available by using the {@link #getVerificationResult(int)} method
 279     *
 280     * @param followManifests
 281     * @return true if all References verify, false if one or more do not verify.
 282     * @throws MissingResourceFailureException if a {@link Reference} does not verify (throws a {@link com.sun.org.apache.xml.internal.security.signature.ReferenceNotInitializedException} because of an uninitialized {@link XMLSignatureInput}


 283     * @see com.sun.org.apache.xml.internal.security.signature.Reference#verify
 284     * @see com.sun.org.apache.xml.internal.security.signature.SignedInfo#verify(boolean)
 285     * @see com.sun.org.apache.xml.internal.security.signature.MissingResourceFailureException
 286     * @throws XMLSecurityException
 287     */
 288    public boolean verifyReferences(boolean followManifests)
 289            throws MissingResourceFailureException, XMLSecurityException {
 290       if (_referencesEl==null) {
 291         this._referencesEl =
 292             XMLUtils.selectDsNodes(this._constructionElement.getFirstChild(),
 293                          Constants._TAG_REFERENCE);

 294       }
 295           if (log.isLoggable(java.util.logging.Level.FINE)) {
 296                 log.log(java.util.logging.Level.FINE, "verify " +_referencesEl.length + " References");
 297         log.log(java.util.logging.Level.FINE, "I am " + (followManifests
 298                            ? ""
 299                            : "not") + " requested to follow nested Manifests");
 300       }
 301       boolean verify = true;
 302 
 303       if (_referencesEl.length==0) {
 304          throw new XMLSecurityException("empty");
 305       }


 306 
 307       this.verificationResults =
 308          new boolean[_referencesEl.length];
 309 
 310       for (int i =
 311               0; i < this._referencesEl.length; i++) {

 312          Reference currentRef =
 313             new Reference(_referencesEl[i], this._baseURI, this);
 314 
 315          this._references.set(i, currentRef);
 316 
 317          /* if only one item does not verify, the whole verification fails */
 318          try {
 319             boolean currentRefVerified = currentRef.verify();
 320 
 321             this.setVerificationResult(i, currentRefVerified);
 322 
 323             if (!currentRefVerified) {
 324                verify = false;
 325             }
 326             if (log.isLoggable(java.util.logging.Level.FINE))
 327                 log.log(java.util.logging.Level.FINE, "The Reference has Type " + currentRef.getType());

 328 
 329             // was verification successful till now and do we want to verify the Manifest?
 330             if (verify && followManifests
 331                     && currentRef.typeIsReferenceToManifest()) {
 332                log.log(java.util.logging.Level.FINE, "We have to follow a nested Manifest");

 333 
 334                 try {
 335                   XMLSignatureInput signedManifestNodes =
 336                     currentRef.dereferenceURIandPerformTransforms(null);
 337                   Set<Node> nl = signedManifestNodes.getNodeSet();
 338                   Manifest referencedManifest = null;
 339                   Iterator<Node> nlIterator = nl.iterator();
 340 
 341                   findManifest: while (nlIterator.hasNext()) {
 342                      Node n =  nlIterator.next();
 343 
 344                      if ((n.getNodeType() == Node.ELEMENT_NODE) && ((Element) n)
 345                              .getNamespaceURI()
 346                              .equals(Constants.SignatureSpecNS) && ((Element) n)
 347                              .getLocalName().equals(Constants._TAG_MANIFEST)) {
 348                         try {
 349                            referencedManifest =
 350                               new Manifest((Element) n,
 351                                            signedManifestNodes.getSourceURI());
 352 
 353                            break findManifest;
 354                         } catch (XMLSecurityException ex) {
 355 


 356                            // Hm, seems not to be a ds:Manifest
 357                         }
 358                      }
 359                   }
 360 
 361                   if (referencedManifest == null) {
 362 
 363                      // The Reference stated that it points to a ds:Manifest
 364                      // but we did not find a ds:Manifest in the signed area
 365                      throw new MissingResourceFailureException("empty",
 366                                                                currentRef);
 367                   }
 368 
 369                   referencedManifest._perManifestResolvers =
 370                      this._perManifestResolvers;
 371                   referencedManifest._resolverProperties =
 372                      this._resolverProperties;
 373 
 374                   boolean referencedManifestValid =
 375                      referencedManifest.verifyReferences(followManifests);
 376 
 377                   if (!referencedManifestValid) {
 378                      verify = false;
 379 
 380                      log.log(java.util.logging.Level.WARNING, "The nested Manifest was invalid (bad)");
 381                   } else {

 382                      log.log(java.util.logging.Level.FINE, "The nested Manifest was valid (good)");
 383                   }

 384                } catch (IOException ex) {
 385                   throw new ReferenceNotInitializedException("empty", ex);
 386                } catch (ParserConfigurationException ex) {
 387                   throw new ReferenceNotInitializedException("empty", ex);
 388                } catch (SAXException ex) {
 389                   throw new ReferenceNotInitializedException("empty", ex);
 390                }
 391             }
 392          } catch (ReferenceNotInitializedException ex) {
 393             Object exArgs[] = { currentRef.getURI() };
 394 
 395             throw new MissingResourceFailureException(
 396                "signature.Verification.Reference.NoInput", exArgs, ex,
 397                currentRef);
 398          }
 399       }
 400 
 401       return verify;
 402    }
 403 
 404    /**
 405     * Method setVerificationResult
 406     *
 407     * @param index
 408     * @param verify
 409     */
 410    private void setVerificationResult(int index, boolean verify)
 411    {
 412 
 413       if (this.verificationResults == null) {
 414          this.verificationResults = new boolean[this.getLength()];
 415       }
 416 
 417       this.verificationResults[index] = verify;
 418    }
 419 
 420    /**
 421     * After verifying a {@link Manifest} or a {@link SignedInfo} using the
 422     * {@link Manifest#verifyReferences()} or {@link SignedInfo#verify()} methods,
 423     * the individual results can be retrieved with this method.
 424     *
 425     * @param index an index of into a {@link Manifest} or a {@link SignedInfo}
 426     * @return the results of reference validation at the specified index
 427     * @throws XMLSecurityException
 428     */
 429    public boolean getVerificationResult(int index) throws XMLSecurityException {
 430 
 431       if ((index < 0) || (index > this.getLength() - 1)) {
 432          Object exArgs[] = { Integer.toString(index),
 433                              Integer.toString(this.getLength()) };
 434          Exception e =
 435             new IndexOutOfBoundsException(I18n
 436                .translate("signature.Verification.IndexOutOfBounds", exArgs));

 437 
 438          throw new XMLSecurityException("generic.EmptyMessage", e);
 439       }
 440 
 441       if (this.verificationResults == null) {
 442          try {
 443             this.verifyReferences();
 444          } catch (Exception ex) {
 445             throw new XMLSecurityException("generic.EmptyMessage", ex);
 446          }
 447       }
 448 
 449       return this.verificationResults[index];
 450    }
 451 
 452    /**
 453     * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute in <code>reference</code> element

 454     *
 455     * @param resolver {@link ResourceResolver} can provide the implemenatin subclass of {@link ResourceResolverSpi} for retrieving resource.

 456     */
 457    public void addResourceResolver(ResourceResolver resolver) {
 458 
 459       if (resolver == null) {
 460           return;
 461       }
 462       if (_perManifestResolvers==null)
 463           _perManifestResolvers = new ArrayList<ResourceResolver>();
 464       this._perManifestResolvers.add(resolver);
 465 
 466    }
 467 
 468    /**
 469     * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute in <code>reference</code> element

 470     *
 471     * @param resolverSpi the implemenatin subclass of {@link ResourceResolverSpi} for retrieving resource.

 472     */
 473    public void addResourceResolver(ResourceResolverSpi resolverSpi) {
 474 
 475       if (resolverSpi == null) {
 476           return;
 477       }
 478       if (_perManifestResolvers==null)
 479                   _perManifestResolvers = new ArrayList<ResourceResolver>();
 480       this._perManifestResolvers.add(new ResourceResolver(resolverSpi));


 481 














 482    }
 483 
 484    /**
 485     * Used to pass parameters like proxy servers etc to the ResourceResolver
 486     * implementation.
 487     *
 488     * @param key the key
 489     * @param value the value
 490     */
 491    public void setResolverProperty(String key, String value) {
 492            if (_resolverProperties==null) {
 493                    _resolverProperties=new HashMap<String, String>(10);
 494            }
 495       this._resolverProperties.put(key, value);
 496    }
 497 
 498    /**
 499     * Returns the value at specified key
 500     *
 501     * @param key the key
 502     * @return the value
 503     */
 504    public String getResolverProperty(String key) {
 505       return this._resolverProperties.get(key);
 506    }
 507 
 508    /**
 509     * Method getSignedContentItem
 510     *
 511     * @param i
 512     * @return The signed content of the i reference.
 513     *
 514     * @throws XMLSignatureException
 515     */
 516    public byte[] getSignedContentItem(int i) throws XMLSignatureException {
 517 
 518       try {
 519          return this.getReferencedContentAfterTransformsItem(i).getBytes();
 520       } catch (IOException ex) {
 521          throw new XMLSignatureException("empty", ex);
 522       } catch (CanonicalizationException ex) {
 523          throw new XMLSignatureException("empty", ex);
 524       } catch (InvalidCanonicalizerException ex) {
 525          throw new XMLSignatureException("empty", ex);
 526       } catch (XMLSecurityException ex) {
 527          throw new XMLSignatureException("empty", ex);
 528       }
 529    }
 530 
 531    /**
 532     * Method getReferencedContentPriorTransformsItem
 533     *
 534     * @param i
 535     * @return The contents before transformation of the reference i.
 536     * @throws XMLSecurityException
 537     */
 538    public XMLSignatureInput getReferencedContentBeforeTransformsItem(int i)
 539            throws XMLSecurityException {
 540       return this.item(i).getContentsBeforeTransformation();
 541    }
 542 
 543    /**
 544     * Method getReferencedContentAfterTransformsItem
 545     *
 546     * @param i
 547     * @return The contents after transformation of the reference i.
 548     * @throws XMLSecurityException
 549     */
 550    public XMLSignatureInput getReferencedContentAfterTransformsItem(int i)
 551            throws XMLSecurityException {
 552       return this.item(i).getContentsAfterTransformation();
 553    }
 554 
 555    /**
 556     * Method getSignedContentLength
 557     *
 558     * @return The nu,ber of references contained in this reference.
 559     */
 560    public int getSignedContentLength() {
 561       return this.getLength();
 562    }
 563 
 564    /**
 565     * Method getBaseLocalName
 566     *
 567     * @inheritDoc
 568     */
 569    public String getBaseLocalName() {
 570       return Constants._TAG_MANIFEST;
 571    }
 572 }
   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.signature;
  24 


  25 import java.io.IOException;
  26 import java.util.ArrayList;
  27 import java.util.HashMap;
  28 import java.util.Iterator;
  29 import java.util.List;

  30 import java.util.Map;
  31 import java.util.Set;
  32 
  33 import javax.xml.parsers.ParserConfigurationException;
  34 
  35 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
  36 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
  37 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
  38 import com.sun.org.apache.xml.internal.security.transforms.Transforms;
  39 import com.sun.org.apache.xml.internal.security.utils.Constants;
  40 import com.sun.org.apache.xml.internal.security.utils.I18n;

  41 import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
  42 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
  43 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
  44 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
  45 import org.w3c.dom.Attr;
  46 import org.w3c.dom.DOMException;
  47 import org.w3c.dom.Document;
  48 import org.w3c.dom.Element;
  49 import org.w3c.dom.Node;
  50 import org.xml.sax.SAXException;
  51 


  52 /**
  53  * Handles <code>&lt;ds:Manifest&gt;</code> elements.
  54  * <p> This element holds the <code>Reference</code> elements</p>

  55  */
  56 public class Manifest extends SignatureElementProxy {
  57     
  58     /**
  59      * The maximum number of references per Manifest, if secure validation is enabled.
  60      */
  61     public static final int MAXIMUM_REFERENCE_COUNT = 30;
  62 
  63     /** {@link org.apache.commons.logging} logging facility */
  64     private static java.util.logging.Logger log = 
  65         java.util.logging.Logger.getLogger(Manifest.class.getName());
  66 
  67     /** Field references */
  68     private List<Reference> references;
  69     private Element[] referencesEl;
  70 
  71     /** Field verificationResults[] */
  72     private boolean verificationResults[] = null;
  73 
  74     /** Field resolverProperties */
  75     private Map<String, String> resolverProperties = null;
  76 
  77     /** Field perManifestResolvers */
  78     private List<ResourceResolver> perManifestResolvers = null;
  79     
  80     private boolean secureValidation;
  81 
  82     /**
  83      * Constructs {@link Manifest}
  84      *
  85      * @param doc the {@link Document} in which <code>XMLsignature</code> is placed
  86      */
  87     public Manifest(Document doc) {

  88         super(doc);
  89 
  90         XMLUtils.addReturnToElement(this.constructionElement);
  91 
  92         this.references = new ArrayList<Reference>();
  93     }
  94 
  95     /**
  96      * Constructor Manifest
  97      *
  98      * @param element
  99      * @param baseURI
 100      * @throws XMLSecurityException
 101      */
 102     public Manifest(Element element, String baseURI) throws XMLSecurityException {
 103         this(element, baseURI, false);
 104         
 105     }
 106     /**
 107      * Constructor Manifest
 108      *
 109      * @param element
 110      * @param baseURI
 111      * @param secureValidation
 112      * @throws XMLSecurityException
 113      */
 114     public Manifest(
 115         Element element, String baseURI, boolean secureValidation
 116     ) throws XMLSecurityException {
 117         super(element, baseURI);
 118         
 119         Attr attr = element.getAttributeNodeNS(null, "Id");
 120         if (attr != null) {
 121             element.setIdAttributeNode(attr, true);
 122         }
 123         this.secureValidation = secureValidation;
 124 
 125         // check out Reference children
 126         this.referencesEl = 
 127             XMLUtils.selectDsNodes(
 128                 this.constructionElement.getFirstChild(), Constants._TAG_REFERENCE
 129             );
 130         int le = this.referencesEl.length;
 131         if (le == 0) {

 132             // At least one Reference must be present. Bad.
 133             Object exArgs[] = { Constants._TAG_REFERENCE, Constants._TAG_MANIFEST };

 134 
 135             throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
 136                                    I18n.translate("xml.WrongContent", exArgs));
 137         }
 138         
 139         if (secureValidation && le > MAXIMUM_REFERENCE_COUNT) {
 140             Object exArgs[] = { le, MAXIMUM_REFERENCE_COUNT };
 141             
 142             throw new XMLSecurityException("signature.tooManyReferences", exArgs);
 143         }
 144 
 145         // create List
 146         this.references = new ArrayList<Reference>(le);
 147 
 148         for (int i = 0; i < le; i++) {
 149             Element refElem = referencesEl[i];
 150             Attr refAttr = refElem.getAttributeNodeNS(null, "Id");
 151             if (refAttr != null) {
 152                 refElem.setIdAttributeNode(refAttr, true);
 153             }
 154             this.references.add(null);
 155         }
 156     }
 157 
 158     /**
 159      * This <code>addDocument</code> method is used to add a new resource to the
 160      * signed info. A {@link com.sun.org.apache.xml.internal.security.signature.Reference} is built
 161      * from the supplied values.
 162      *
 163      * @param baseURI the URI of the resource where the XML instance was stored
 164      * @param referenceURI <code>URI</code> attribute in <code>Reference</code> for specifying 
 165      * where data is
 166      * @param transforms com.sun.org.apache.xml.internal.security.signature.Transforms object with an ordered 
 167      * list of transformations to be performed.
 168      * @param digestURI The digest algorithm URI to be used.
 169      * @param referenceId
 170      * @param referenceType
 171      * @throws XMLSignatureException
 172      */
 173     public void addDocument(
 174         String baseURI, String referenceURI, Transforms transforms, 
 175         String digestURI, String referenceId, String referenceType
 176     ) throws XMLSignatureException {
 177         // the this.doc is handed implicitly by the this.getOwnerDocument()
 178         Reference ref = 
 179             new Reference(this.doc, baseURI, referenceURI, this, transforms, digestURI);
 180 
 181         if (referenceId != null) {
 182             ref.setId(referenceId);
 183         }
 184 
 185         if (referenceType != null) {
 186             ref.setType(referenceType);
 187         }
 188 
 189         // add Reference object to our cache vector
 190         this.references.add(ref);
 191 
 192         // add the Element of the Reference object to the Manifest/SignedInfo
 193         this.constructionElement.appendChild(ref.getElement());
 194         XMLUtils.addReturnToElement(this.constructionElement);
 195     }
 196 
 197     /**
 198      * The calculation of the DigestValues in the References must be after the
 199      * References are already added to the document and during the signing
 200      * process. This ensures that all necessary data is in place.
 201      *
 202      * @throws ReferenceNotInitializedException
 203      * @throws XMLSignatureException
 204      */
 205     public void generateDigestValues()
 206         throws XMLSignatureException, ReferenceNotInitializedException {

 207         for (int i = 0; i < this.getLength(); i++) {

 208             // update the cached Reference object, the Element content is automatically updated
 209             Reference currentRef = this.references.get(i);

 210             currentRef.generateDigestValue();
 211         }
 212     }
 213 
 214     /**
 215      * Return the nonnegative number of added references.
 216      *
 217      * @return the number of references
 218      */
 219     public int getLength() {
 220         return this.references.size();
 221     }
 222 
 223     /**
 224      * Return the <it>i</it><sup>th</sup> reference. Valid <code>i</code>
 225      * values are 0 to <code>{link@ getSize}-1</code>.
 226      *
 227      * @param i Index of the requested {@link Reference}
 228      * @return the <it>i</it><sup>th</sup> reference
 229      * @throws XMLSecurityException
 230      */
 231     public Reference item(int i) throws XMLSecurityException {
 232         if (this.references.get(i) == null) {


 233             // not yet constructed, so _we_ have to            
 234             Reference ref = 
 235                 new Reference(referencesEl[i], this.baseURI, this, secureValidation);
 236 
 237             this.references.set(i, ref);
 238         }
 239 
 240         return this.references.get(i);

 241     }
 242 
 243     /**
 244      * Sets the <code>Id</code> attribute
 245      *
 246      * @param Id the <code>Id</code> attribute in <code>ds:Manifest</code>
 247      */
 248     public void setId(String Id) {

 249         if (Id != null) {
 250             this.constructionElement.setAttributeNS(null, Constants._ATT_ID, Id);
 251             this.constructionElement.setIdAttributeNS(null, Constants._ATT_ID, true);
 252         }
 253     }
 254 
 255     /**
 256      * Returns the <code>Id</code> attribute
 257      *
 258      * @return the <code>Id</code> attribute in <code>ds:Manifest</code>
 259      */
 260     public String getId() {
 261         return this.constructionElement.getAttributeNS(null, Constants._ATT_ID);
 262     }
 263 
 264     /**
 265      * Used to do a <A HREF="http://www.w3.org/TR/xmldsig-core/#def-ValidationReference">reference
 266      * validation</A> of all enclosed references using the {@link Reference#verify} method.
 267      *
 268      * <p>This step loops through all {@link Reference}s and does verify the hash
 269      * values. If one or more verifications fail, the method returns
 270      * <code>false</code>. If <i>all</i> verifications are successful,
 271      * it returns <code>true</code>. The results of the individual reference
 272      * validations are available by using the {@link #getVerificationResult(int)} method
 273      *
 274      * @return true if all References verify, false if one or more do not verify.
 275      * @throws MissingResourceFailureException if a {@link Reference} does not verify 
 276      * (throws a {@link com.sun.org.apache.xml.internal.security.signature.ReferenceNotInitializedException} 
 277      * because of an uninitialized {@link XMLSignatureInput}
 278      * @see com.sun.org.apache.xml.internal.security.signature.Reference#verify
 279      * @see com.sun.org.apache.xml.internal.security.signature.SignedInfo#verify()
 280      * @see com.sun.org.apache.xml.internal.security.signature.MissingResourceFailureException
 281      * @throws XMLSecurityException
 282      */
 283     public boolean verifyReferences()
 284         throws MissingResourceFailureException, XMLSecurityException {
 285         return this.verifyReferences(false);
 286     }
 287 
 288     /**
 289      * Used to do a <A HREF="http://www.w3.org/TR/xmldsig-core/#def-ValidationReference">reference
 290      * validation</A> of all enclosed references using the {@link Reference#verify} method.
 291      *
 292      * <p>This step loops through all {@link Reference}s and does verify the hash
 293      * values. If one or more verifications fail, the method returns
 294      * <code>false</code>. If <i>all</i> verifications are successful,
 295      * it returns <code>true</code>. The results of the individual reference
 296      * validations are available by using the {@link #getVerificationResult(int)} method
 297      *
 298      * @param followManifests
 299      * @return true if all References verify, false if one or more do not verify.
 300      * @throws MissingResourceFailureException if a {@link Reference} does not verify 
 301      * (throws a {@link com.sun.org.apache.xml.internal.security.signature.ReferenceNotInitializedException} 
 302      * because of an uninitialized {@link XMLSignatureInput}
 303      * @see com.sun.org.apache.xml.internal.security.signature.Reference#verify
 304      * @see com.sun.org.apache.xml.internal.security.signature.SignedInfo#verify(boolean)
 305      * @see com.sun.org.apache.xml.internal.security.signature.MissingResourceFailureException
 306      * @throws XMLSecurityException
 307      */
 308     public boolean verifyReferences(boolean followManifests)
 309         throws MissingResourceFailureException, XMLSecurityException {
 310         if (referencesEl == null) {
 311             this.referencesEl =  
 312                 XMLUtils.selectDsNodes(
 313                     this.constructionElement.getFirstChild(), Constants._TAG_REFERENCE
 314                 );
 315         }
 316         if (log.isLoggable(java.util.logging.Level.FINE)) {
 317             log.log(java.util.logging.Level.FINE, "verify " + referencesEl.length + " References");
 318             log.log(java.util.logging.Level.FINE, "I am " + (followManifests
 319                 ? "" : "not") + " requested to follow nested Manifests");

 320         }
 321         if (referencesEl.length == 0) {


 322             throw new XMLSecurityException("empty");
 323         }
 324         if (secureValidation && referencesEl.length > MAXIMUM_REFERENCE_COUNT) {
 325             Object exArgs[] = { referencesEl.length, MAXIMUM_REFERENCE_COUNT };
 326                         
 327             throw new XMLSecurityException("signature.tooManyReferences", exArgs);
 328         }
 329 
 330         this.verificationResults = new boolean[referencesEl.length];
 331         boolean verify = true;
 332         for (int i = 0; i < this.referencesEl.length; i++) {
 333             Reference currentRef =
 334                 new Reference(referencesEl[i], this.baseURI, this, secureValidation);
 335 
 336             this.references.set(i, currentRef);
 337 
 338             // if only one item does not verify, the whole verification fails
 339             try {
 340                 boolean currentRefVerified = currentRef.verify();
 341 
 342                 this.setVerificationResult(i, currentRefVerified);
 343 
 344                 if (!currentRefVerified) {
 345                     verify = false;
 346                 }
 347                 if (log.isLoggable(java.util.logging.Level.FINE)) {
 348                     log.log(java.util.logging.Level.FINE, "The Reference has Type " + currentRef.getType());
 349                 }
 350 
 351                 // was verification successful till now and do we want to verify the Manifest?
 352                 if (verify && followManifests && currentRef.typeIsReferenceToManifest()) {
 353                     if (log.isLoggable(java.util.logging.Level.FINE)) {
 354                         log.log(java.util.logging.Level.FINE, "We have to follow a nested Manifest");
 355                     }
 356 
 357                     try {
 358                         XMLSignatureInput signedManifestNodes =
 359                             currentRef.dereferenceURIandPerformTransforms(null);
 360                         Set<Node> nl = signedManifestNodes.getNodeSet();
 361                         Manifest referencedManifest = null;
 362                         Iterator<Node> nlIterator = nl.iterator();
 363 
 364                         findManifest: while (nlIterator.hasNext()) {
 365                             Node n = nlIterator.next();
 366 
 367                             if ((n.getNodeType() == Node.ELEMENT_NODE) 
 368                                 && ((Element) n).getNamespaceURI().equals(Constants.SignatureSpecNS) 
 369                                 && ((Element) n).getLocalName().equals(Constants._TAG_MANIFEST)
 370                             ) {
 371                                 try {
 372                                     referencedManifest =
 373                                         new Manifest(
 374                                              (Element)n, signedManifestNodes.getSourceURI(), secureValidation
 375                                         );
 376                                     break findManifest;
 377                                 } catch (XMLSecurityException ex) {
 378                                     if (log.isLoggable(java.util.logging.Level.FINE)) {
 379                                         log.log(java.util.logging.Level.FINE, ex.getMessage(), ex);
 380                                     }
 381                                     // Hm, seems not to be a ds:Manifest
 382                                 }
 383                             }
 384                         }
 385 
 386                         if (referencedManifest == null) {

 387                             // The Reference stated that it points to a ds:Manifest
 388                             // but we did not find a ds:Manifest in the signed area
 389                             throw new MissingResourceFailureException("empty", currentRef);

 390                         }
 391 
 392                         referencedManifest.perManifestResolvers = this.perManifestResolvers;
 393                         referencedManifest.resolverProperties = this.resolverProperties;


 394 
 395                         boolean referencedManifestValid =
 396                             referencedManifest.verifyReferences(followManifests);
 397 
 398                         if (!referencedManifestValid) {
 399                             verify = false;
 400 
 401                             log.log(java.util.logging.Level.WARNING, "The nested Manifest was invalid (bad)");
 402                         } else {
 403                             if (log.isLoggable(java.util.logging.Level.FINE)) {
 404                                 log.log(java.util.logging.Level.FINE, "The nested Manifest was valid (good)");
 405                             }
 406                         }
 407                     } catch (IOException ex) {
 408                         throw new ReferenceNotInitializedException("empty", ex);
 409                     } catch (ParserConfigurationException ex) {
 410                         throw new ReferenceNotInitializedException("empty", ex);
 411                     } catch (SAXException ex) {
 412                         throw new ReferenceNotInitializedException("empty", ex);
 413                     }
 414                 }
 415             } catch (ReferenceNotInitializedException ex) {
 416                 Object exArgs[] = { currentRef.getURI() };
 417 
 418                 throw new MissingResourceFailureException(
 419                     "signature.Verification.Reference.NoInput", exArgs, ex, currentRef
 420                 );
 421             }
 422         }
 423 
 424         return verify;
 425     }
 426 
 427     /**
 428      * Method setVerificationResult
 429      *
 430      * @param index
 431      * @param verify
 432      */
 433     private void setVerificationResult(int index, boolean verify) {


 434         if (this.verificationResults == null) {
 435             this.verificationResults = new boolean[this.getLength()];
 436         }
 437 
 438         this.verificationResults[index] = verify;
 439     }
 440 
 441     /**
 442      * After verifying a {@link Manifest} or a {@link SignedInfo} using the
 443      * {@link Manifest#verifyReferences()} or {@link SignedInfo#verify()} methods,
 444      * the individual results can be retrieved with this method.
 445      *
 446      * @param index an index of into a {@link Manifest} or a {@link SignedInfo}
 447      * @return the results of reference validation at the specified index
 448      * @throws XMLSecurityException
 449      */
 450     public boolean getVerificationResult(int index) throws XMLSecurityException {

 451         if ((index < 0) || (index > this.getLength() - 1)) {
 452             Object exArgs[] = { Integer.toString(index), Integer.toString(this.getLength()) };

 453             Exception e =
 454                 new IndexOutOfBoundsException(
 455                     I18n.translate("signature.Verification.IndexOutOfBounds", exArgs)
 456                 );
 457 
 458             throw new XMLSecurityException("generic.EmptyMessage", e);
 459         }
 460 
 461         if (this.verificationResults == null) {
 462             try {
 463                 this.verifyReferences();
 464             } catch (Exception ex) {
 465                 throw new XMLSecurityException("generic.EmptyMessage", ex);
 466             }
 467         }
 468 
 469         return this.verificationResults[index];
 470     }
 471 
 472     /**
 473      * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute 
 474      * in <code>reference</code> element
 475      *
 476      * @param resolver {@link ResourceResolver} can provide the implemenatin subclass of 
 477      * {@link ResourceResolverSpi} for retrieving resource.
 478      */
 479     public void addResourceResolver(ResourceResolver resolver) {

 480         if (resolver == null) {
 481             return;
 482         }
 483         if (perManifestResolvers == null) {
 484             perManifestResolvers = new ArrayList<ResourceResolver>();
 485         }
 486         this.perManifestResolvers.add(resolver);
 487     }
 488 
 489     /**
 490      * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute 
 491      * in <code>reference</code> element
 492      *
 493      * @param resolverSpi the implementation subclass of {@link ResourceResolverSpi} for 
 494      * retrieving the resource.
 495      */
 496     public void addResourceResolver(ResourceResolverSpi resolverSpi) {

 497         if (resolverSpi == null) {
 498             return;
 499         }
 500         if (perManifestResolvers == null) {
 501             perManifestResolvers = new ArrayList<ResourceResolver>();
 502         }
 503         perManifestResolvers.add(new ResourceResolver(resolverSpi));
 504     }
 505 
 506     /**
 507      * Get the Per-Manifest Resolver List
 508      * @return the per-manifest Resolver List
 509      */
 510     public List<ResourceResolver> getPerManifestResolvers() {
 511         return perManifestResolvers;
 512     }
 513     
 514     /**
 515      * Get the resolver property map
 516      * @return the resolver property map
 517      */
 518     public Map<String, String> getResolverProperties() {
 519         return resolverProperties;
 520     }
 521     
 522     /**
 523      * Used to pass parameters like proxy servers etc to the ResourceResolver
 524      * implementation.
 525      *
 526      * @param key the key
 527      * @param value the value
 528      */
 529     public void setResolverProperty(String key, String value) {
 530         if (resolverProperties == null) {
 531             resolverProperties = new HashMap<String, String>(10);
 532         }
 533         this.resolverProperties.put(key, value);
 534     }
 535 
 536     /**
 537      * Returns the value at specified key
 538      *
 539      * @param key the key
 540      * @return the value
 541      */
 542     public String getResolverProperty(String key) {
 543         return this.resolverProperties.get(key);
 544     }
 545 
 546     /**
 547      * Method getSignedContentItem
 548      *
 549      * @param i
 550      * @return The signed content of the i reference.
 551      *
 552      * @throws XMLSignatureException
 553      */
 554     public byte[] getSignedContentItem(int i) throws XMLSignatureException {

 555         try {
 556             return this.getReferencedContentAfterTransformsItem(i).getBytes();
 557         } catch (IOException ex) {
 558             throw new XMLSignatureException("empty", ex);
 559         } catch (CanonicalizationException ex) {
 560             throw new XMLSignatureException("empty", ex);
 561         } catch (InvalidCanonicalizerException ex) {
 562             throw new XMLSignatureException("empty", ex);
 563         } catch (XMLSecurityException ex) {
 564             throw new XMLSignatureException("empty", ex);
 565         }
 566     }
 567 
 568     /**
 569      * Method getReferencedContentPriorTransformsItem
 570      *
 571      * @param i
 572      * @return The contents before transformation of the reference i.
 573      * @throws XMLSecurityException
 574      */
 575     public XMLSignatureInput getReferencedContentBeforeTransformsItem(int i)
 576         throws XMLSecurityException {
 577         return this.item(i).getContentsBeforeTransformation();
 578     }
 579 
 580     /**
 581      * Method getReferencedContentAfterTransformsItem
 582      *
 583      * @param i
 584      * @return The contents after transformation of the reference i.
 585      * @throws XMLSecurityException
 586      */
 587     public XMLSignatureInput getReferencedContentAfterTransformsItem(int i)
 588         throws XMLSecurityException {
 589         return this.item(i).getContentsAfterTransformation();
 590     }
 591 
 592     /**
 593      * Method getSignedContentLength
 594      *
 595      * @return The number of references contained in this reference.
 596      */
 597     public int getSignedContentLength() {
 598         return this.getLength();
 599     }
 600 
 601     /**
 602      * Method getBaseLocalName
 603      *
 604      * @inheritDoc
 605      */
 606     public String getBaseLocalName() {
 607         return Constants._TAG_MANIFEST;
 608     }
 609 }