View Javadoc
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.io.OutputStream;
27  import java.security.Key;
28  import java.security.PublicKey;
29  import java.security.cert.X509Certificate;
30  
31  import javax.crypto.SecretKey;
32  
33  import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;
34  import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
35  import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
36  import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
37  import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
38  import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
39  import com.sun.org.apache.xml.internal.security.keys.KeyInfo;
40  import com.sun.org.apache.xml.internal.security.keys.content.X509Data;
41  import com.sun.org.apache.xml.internal.security.transforms.Transforms;
42  import com.sun.org.apache.xml.internal.security.utils.Base64;
43  import com.sun.org.apache.xml.internal.security.utils.Constants;
44  import com.sun.org.apache.xml.internal.security.utils.I18n;
45  import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
46  import com.sun.org.apache.xml.internal.security.utils.SignerOutputStream;
47  import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream;
48  import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
49  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
50  import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
51  import org.w3c.dom.Attr;
52  import org.w3c.dom.Document;
53  import org.w3c.dom.Element;
54  import org.w3c.dom.Node;
55  import org.w3c.dom.NodeList;
56  import org.w3c.dom.Text;
57  
58  /**
59   * Handles <code>&lt;ds:Signature&gt;</code> elements.
60   * This is the main class that deals with creating and verifying signatures.
61   *
62   * <p>There are 2 types of constructors for this class. The ones that take a
63   * document, baseURI and 1 or more Java Objects. This is mostly used for
64   * signing purposes.
65   * The other constructor is the one that takes a DOM Element and a baseURI.
66   * This is used mostly with for verifying, when you have a SignatureElement.
67   *
68   * There are a few different types of methods:
69   * <ul><li>The addDocument* methods are used to add References with optional
70   * transforms during signing. </li>
71   * <li>addKeyInfo* methods are to add Certificates and Keys to the
72   * KeyInfo tags during signing. </li>
73   * <li>appendObject allows a user to add any XML Structure as an
74   * ObjectContainer during signing.</li>
75   * <li>sign and checkSignatureValue methods are used to sign and validate the
76   * signature. </li></ul>
77   */
78  public final class XMLSignature extends SignatureElementProxy {
79  
80      /** MAC - Required HMAC-SHA1 */
81      public static final String ALGO_ID_MAC_HMAC_SHA1 =
82          Constants.SignatureSpecNS + "hmac-sha1";
83  
84      /** Signature - Required DSAwithSHA1 (DSS) */
85      public static final String ALGO_ID_SIGNATURE_DSA =
86          Constants.SignatureSpecNS + "dsa-sha1";
87  
88      /** Signature - Recommended RSAwithSHA1 */
89      public static final String ALGO_ID_SIGNATURE_RSA =
90          Constants.SignatureSpecNS + "rsa-sha1";
91  
92      /** Signature - Recommended RSAwithSHA1 */
93      public static final String ALGO_ID_SIGNATURE_RSA_SHA1 =
94          Constants.SignatureSpecNS + "rsa-sha1";
95  
96      /** Signature - NOT Recommended RSAwithMD5 */
97      public static final String ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5 =
98          Constants.MoreAlgorithmsSpecNS + "rsa-md5";
99  
100     /** Signature - Optional RSAwithRIPEMD160 */
101     public static final String ALGO_ID_SIGNATURE_RSA_RIPEMD160 =
102         Constants.MoreAlgorithmsSpecNS + "rsa-ripemd160";
103 
104     /** Signature - Optional RSAwithSHA256 */
105     public static final String ALGO_ID_SIGNATURE_RSA_SHA256 =
106         Constants.MoreAlgorithmsSpecNS + "rsa-sha256";
107 
108     /** Signature - Optional RSAwithSHA384 */
109     public static final String ALGO_ID_SIGNATURE_RSA_SHA384 =
110         Constants.MoreAlgorithmsSpecNS + "rsa-sha384";
111 
112     /** Signature - Optional RSAwithSHA512 */
113     public static final String ALGO_ID_SIGNATURE_RSA_SHA512 =
114         Constants.MoreAlgorithmsSpecNS + "rsa-sha512";
115 
116     /** HMAC - NOT Recommended HMAC-MD5 */
117     public static final String ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5 =
118         Constants.MoreAlgorithmsSpecNS + "hmac-md5";
119 
120     /** HMAC - Optional HMAC-RIPEMD160 */
121     public static final String ALGO_ID_MAC_HMAC_RIPEMD160 =
122         Constants.MoreAlgorithmsSpecNS + "hmac-ripemd160";
123 
124     /** HMAC - Optional HMAC-SHA256 */
125     public static final String ALGO_ID_MAC_HMAC_SHA256 =
126         Constants.MoreAlgorithmsSpecNS + "hmac-sha256";
127 
128     /** HMAC - Optional HMAC-SHA284 */
129     public static final String ALGO_ID_MAC_HMAC_SHA384 =
130         Constants.MoreAlgorithmsSpecNS + "hmac-sha384";
131 
132     /** HMAC - Optional HMAC-SHA512 */
133     public static final String ALGO_ID_MAC_HMAC_SHA512 =
134         Constants.MoreAlgorithmsSpecNS + "hmac-sha512";
135 
136     /**Signature - Optional ECDSAwithSHA1 */
137     public static final String ALGO_ID_SIGNATURE_ECDSA_SHA1 =
138         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1";
139 
140     /**Signature - Optional ECDSAwithSHA256 */
141     public static final String ALGO_ID_SIGNATURE_ECDSA_SHA256 =
142         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
143 
144     /**Signature - Optional ECDSAwithSHA384 */
145     public static final String ALGO_ID_SIGNATURE_ECDSA_SHA384 =
146         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384";
147 
148     /**Signature - Optional ECDSAwithSHA512 */
149     public static final String ALGO_ID_SIGNATURE_ECDSA_SHA512 =
150         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";
151 
152     /** {@link org.apache.commons.logging} logging facility */
153     private static java.util.logging.Logger log =
154         java.util.logging.Logger.getLogger(XMLSignature.class.getName());
155 
156     /** ds:Signature.ds:SignedInfo element */
157     private SignedInfo signedInfo;
158 
159     /** ds:Signature.ds:KeyInfo */
160     private KeyInfo keyInfo;
161 
162     /**
163      * Checking the digests in References in a Signature are mandatory, but for
164      * References inside a Manifest it is application specific. This boolean is
165      * to indicate that the References inside Manifests should be validated.
166      */
167     private boolean followManifestsDuringValidation = false;
168 
169     private Element signatureValueElement;
170 
171     private static final int MODE_SIGN = 0;
172     private static final int MODE_VERIFY = 1;
173     private int state = MODE_SIGN;
174 
175     /**
176      * This creates a new <CODE>ds:Signature</CODE> Element and adds an empty
177      * <CODE>ds:SignedInfo</CODE>.
178      * The <code>ds:SignedInfo</code> is initialized with the specified Signature
179      * algorithm and Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS which is REQUIRED
180      * by the spec. This method's main use is for creating a new signature.
181      *
182      * @param doc Document in which the signature will be appended after creation.
183      * @param baseURI URI to be used as context for all relative URIs.
184      * @param signatureMethodURI signature algorithm to use.
185      * @throws XMLSecurityException
186      */
187     public XMLSignature(Document doc, String baseURI, String signatureMethodURI)
188         throws XMLSecurityException {
189         this(doc, baseURI, signatureMethodURI, 0, Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
190     }
191 
192     /**
193      * Constructor XMLSignature
194      *
195      * @param doc
196      * @param baseURI
197      * @param signatureMethodURI the Signature method to be used.
198      * @param hmacOutputLength
199      * @throws XMLSecurityException
200      */
201     public XMLSignature(Document doc, String baseURI, String signatureMethodURI,
202                         int hmacOutputLength) throws XMLSecurityException {
203         this(
204             doc, baseURI, signatureMethodURI, hmacOutputLength,
205             Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS
206         );
207     }
208 
209     /**
210      * Constructor XMLSignature
211      *
212      * @param doc
213      * @param baseURI
214      * @param signatureMethodURI the Signature method to be used.
215      * @param canonicalizationMethodURI the canonicalization algorithm to be
216      * used to c14nize the SignedInfo element.
217      * @throws XMLSecurityException
218      */
219     public XMLSignature(
220         Document doc,
221         String baseURI,
222         String signatureMethodURI,
223         String canonicalizationMethodURI
224     ) throws XMLSecurityException {
225         this(doc, baseURI, signatureMethodURI, 0, canonicalizationMethodURI);
226     }
227 
228     /**
229      * Constructor XMLSignature
230      *
231      * @param doc
232      * @param baseURI
233      * @param signatureMethodURI
234      * @param hmacOutputLength
235      * @param canonicalizationMethodURI
236      * @throws XMLSecurityException
237      */
238     public XMLSignature(
239         Document doc,
240         String baseURI,
241         String signatureMethodURI,
242         int hmacOutputLength,
243         String canonicalizationMethodURI
244     ) throws XMLSecurityException {
245         super(doc);
246 
247         String xmlnsDsPrefix = getDefaultPrefix(Constants.SignatureSpecNS);
248         if (xmlnsDsPrefix == null || xmlnsDsPrefix.length() == 0) {
249             this.constructionElement.setAttributeNS(
250                 Constants.NamespaceSpecNS, "xmlns", Constants.SignatureSpecNS
251             );
252         } else {
253             this.constructionElement.setAttributeNS(
254                 Constants.NamespaceSpecNS, "xmlns:" + xmlnsDsPrefix, Constants.SignatureSpecNS
255             );
256         }
257         XMLUtils.addReturnToElement(this.constructionElement);
258 
259         this.baseURI = baseURI;
260         this.signedInfo =
261             new SignedInfo(
262                 this.doc, signatureMethodURI, hmacOutputLength, canonicalizationMethodURI
263             );
264 
265         this.constructionElement.appendChild(this.signedInfo.getElement());
266         XMLUtils.addReturnToElement(this.constructionElement);
267 
268         // create an empty SignatureValue; this is filled by setSignatureValueElement
269         signatureValueElement =
270             XMLUtils.createElementInSignatureSpace(this.doc, Constants._TAG_SIGNATUREVALUE);
271 
272         this.constructionElement.appendChild(signatureValueElement);
273         XMLUtils.addReturnToElement(this.constructionElement);
274     }
275 
276     /**
277      *  Creates a XMLSignature in a Document
278      * @param doc
279      * @param baseURI
280      * @param SignatureMethodElem
281      * @param CanonicalizationMethodElem
282      * @throws XMLSecurityException
283      */
284     public XMLSignature(
285         Document doc,
286         String baseURI,
287         Element SignatureMethodElem,
288         Element CanonicalizationMethodElem
289     ) throws XMLSecurityException {
290         super(doc);
291 
292         String xmlnsDsPrefix = getDefaultPrefix(Constants.SignatureSpecNS);
293         if (xmlnsDsPrefix == null || xmlnsDsPrefix.length() == 0) {
294             this.constructionElement.setAttributeNS(
295                 Constants.NamespaceSpecNS, "xmlns", Constants.SignatureSpecNS
296             );
297         } else {
298             this.constructionElement.setAttributeNS(
299                 Constants.NamespaceSpecNS, "xmlns:" + xmlnsDsPrefix, Constants.SignatureSpecNS
300             );
301         }
302         XMLUtils.addReturnToElement(this.constructionElement);
303 
304         this.baseURI = baseURI;
305         this.signedInfo =
306             new SignedInfo(this.doc, SignatureMethodElem, CanonicalizationMethodElem);
307 
308         this.constructionElement.appendChild(this.signedInfo.getElement());
309         XMLUtils.addReturnToElement(this.constructionElement);
310 
311         // create an empty SignatureValue; this is filled by setSignatureValueElement
312         signatureValueElement =
313             XMLUtils.createElementInSignatureSpace(this.doc, Constants._TAG_SIGNATUREVALUE);
314 
315         this.constructionElement.appendChild(signatureValueElement);
316         XMLUtils.addReturnToElement(this.constructionElement);
317     }
318 
319     /**
320      * This will parse the element and construct the Java Objects.
321      * That will allow a user to validate the signature.
322      *
323      * @param element ds:Signature element that contains the whole signature
324      * @param baseURI URI to be prepended to all relative URIs
325      * @throws XMLSecurityException
326      * @throws XMLSignatureException if the signature is badly formatted
327      */
328     public XMLSignature(Element element, String baseURI)
329         throws XMLSignatureException, XMLSecurityException {
330         this(element, baseURI, false);
331     }
332 
333     /**
334      * This will parse the element and construct the Java Objects.
335      * That will allow a user to validate the signature.
336      *
337      * @param element ds:Signature element that contains the whole signature
338      * @param baseURI URI to be prepended to all relative URIs
339      * @param secureValidation whether secure secureValidation is enabled or not
340      * @throws XMLSecurityException
341      * @throws XMLSignatureException if the signature is badly formatted
342      */
343     public XMLSignature(Element element, String baseURI, boolean secureValidation)
344         throws XMLSignatureException, XMLSecurityException {
345         super(element, baseURI);
346 
347         // check out SignedInfo child
348         Element signedInfoElem = XMLUtils.getNextElement(element.getFirstChild());
349 
350         // check to see if it is there
351         if (signedInfoElem == null) {
352             Object exArgs[] = { Constants._TAG_SIGNEDINFO, Constants._TAG_SIGNATURE };
353             throw new XMLSignatureException("xml.WrongContent", exArgs);
354         }
355 
356         // create a SignedInfo object from that element
357         this.signedInfo = new SignedInfo(signedInfoElem, baseURI, secureValidation);
358         // get signedInfoElem again in case it has changed
359         signedInfoElem = XMLUtils.getNextElement(element.getFirstChild());
360 
361         // check out SignatureValue child
362         this.signatureValueElement =
363             XMLUtils.getNextElement(signedInfoElem.getNextSibling());
364 
365         // check to see if it exists
366         if (signatureValueElement == null) {
367             Object exArgs[] = { Constants._TAG_SIGNATUREVALUE, Constants._TAG_SIGNATURE };
368             throw new XMLSignatureException("xml.WrongContent", exArgs);
369         }
370         Attr signatureValueAttr = signatureValueElement.getAttributeNodeNS(null, "Id");
371         if (signatureValueAttr != null) {
372             signatureValueElement.setIdAttributeNode(signatureValueAttr, true);
373         }
374 
375         // <element ref="ds:KeyInfo" minOccurs="0"/>
376         Element keyInfoElem =
377             XMLUtils.getNextElement(signatureValueElement.getNextSibling());
378 
379         // If it exists use it, but it's not mandatory
380         if (keyInfoElem != null
381             && keyInfoElem.getNamespaceURI().equals(Constants.SignatureSpecNS)
382             && keyInfoElem.getLocalName().equals(Constants._TAG_KEYINFO)) {
383             this.keyInfo = new KeyInfo(keyInfoElem, baseURI);
384             this.keyInfo.setSecureValidation(secureValidation);
385         }
386 
387         // <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
388         Element objectElem =
389             XMLUtils.getNextElement(signatureValueElement.getNextSibling());
390         while (objectElem != null) {
391             Attr objectAttr = objectElem.getAttributeNodeNS(null, "Id");
392             if (objectAttr != null) {
393                 objectElem.setIdAttributeNode(objectAttr, true);
394             }
395 
396             NodeList nodes = objectElem.getChildNodes();
397             int length = nodes.getLength();
398             // Register Ids of the Object child elements
399             for (int i = 0; i < length; i++) {
400                 Node child = nodes.item(i);
401                 if (child.getNodeType() == Node.ELEMENT_NODE) {
402                     Element childElem = (Element)child;
403                     String tag = childElem.getLocalName();
404                     if (tag.equals("Manifest")) {
405                         new Manifest(childElem, baseURI);
406                     } else if (tag.equals("SignatureProperties")) {
407                         new SignatureProperties(childElem, baseURI);
408                     }
409                 }
410             }
411 
412             objectElem = XMLUtils.getNextElement(objectElem.getNextSibling());
413         }
414 
415         this.state = MODE_VERIFY;
416     }
417 
418     /**
419      * Sets the <code>Id</code> attribute
420      *
421      * @param id Id value for the id attribute on the Signature Element
422      */
423     public void setId(String id) {
424         if (id != null) {
425             this.constructionElement.setAttributeNS(null, Constants._ATT_ID, id);
426             this.constructionElement.setIdAttributeNS(null, Constants._ATT_ID, true);
427         }
428     }
429 
430     /**
431      * Returns the <code>Id</code> attribute
432      *
433      * @return the <code>Id</code> attribute
434      */
435     public String getId() {
436         return this.constructionElement.getAttributeNS(null, Constants._ATT_ID);
437     }
438 
439     /**
440      * Returns the completely parsed <code>SignedInfo</code> object.
441      *
442      * @return the completely parsed <code>SignedInfo</code> object.
443      */
444     public SignedInfo getSignedInfo() {
445         return this.signedInfo;
446     }
447 
448     /**
449      * Returns the octet value of the SignatureValue element.
450      * Throws an XMLSignatureException if it has no or wrong content.
451      *
452      * @return the value of the SignatureValue element.
453      * @throws XMLSignatureException If there is no content
454      */
455     public byte[] getSignatureValue() throws XMLSignatureException {
456         try {
457             return Base64.decode(signatureValueElement);
458         } catch (Base64DecodingException ex) {
459             throw new XMLSignatureException("empty", ex);
460         }
461     }
462 
463     /**
464      * Base64 encodes and sets the bytes as the content of the SignatureValue
465      * Node.
466      *
467      * @param bytes bytes to be used by SignatureValue before Base64 encoding
468      */
469     private void setSignatureValueElement(byte[] bytes) {
470 
471         while (signatureValueElement.hasChildNodes()) {
472             signatureValueElement.removeChild(signatureValueElement.getFirstChild());
473         }
474 
475         String base64codedValue = Base64.encode(bytes);
476 
477         if (base64codedValue.length() > 76 && !XMLUtils.ignoreLineBreaks()) {
478             base64codedValue = "\n" + base64codedValue + "\n";
479         }
480 
481         Text t = this.doc.createTextNode(base64codedValue);
482         signatureValueElement.appendChild(t);
483     }
484 
485     /**
486      * Returns the KeyInfo child. If we are in signing mode and the KeyInfo
487      * does not exist yet, it is created on demand and added to the Signature.
488      * <br>
489      * This allows to add arbitrary content to the KeyInfo during signing.
490      *
491      * @return the KeyInfo object
492      */
493     public KeyInfo getKeyInfo() {
494         // check to see if we are signing and if we have to create a keyinfo
495         if (this.state == MODE_SIGN && this.keyInfo == null) {
496 
497             // create the KeyInfo
498             this.keyInfo = new KeyInfo(this.doc);
499 
500             // get the Element from KeyInfo
501             Element keyInfoElement = this.keyInfo.getElement();
502             Element firstObject =
503                 XMLUtils.selectDsNode(
504                     this.constructionElement.getFirstChild(), Constants._TAG_OBJECT, 0
505                 );
506 
507             if (firstObject != null) {
508                 // add it before the object
509                 this.constructionElement.insertBefore(keyInfoElement, firstObject);
510                 XMLUtils.addReturnBeforeChild(this.constructionElement, firstObject);
511             } else {
512                 // add it as the last element to the signature
513                 this.constructionElement.appendChild(keyInfoElement);
514                 XMLUtils.addReturnToElement(this.constructionElement);
515             }
516         }
517 
518         return this.keyInfo;
519     }
520 
521     /**
522      * Appends an Object (not a <code>java.lang.Object</code> but an Object
523      * element) to the Signature. Please note that this is only possible
524      * when signing.
525      *
526      * @param object ds:Object to be appended.
527      * @throws XMLSignatureException When this object is used to verify.
528      */
529     public void appendObject(ObjectContainer object) throws XMLSignatureException {
530         //try {
531         //if (this.state != MODE_SIGN) {
532         // throw new XMLSignatureException(
533         //  "signature.operationOnlyBeforeSign");
534         //}
535 
536         this.constructionElement.appendChild(object.getElement());
537         XMLUtils.addReturnToElement(this.constructionElement);
538         //} catch (XMLSecurityException ex) {
539         // throw new XMLSignatureException("empty", ex);
540         //}
541     }
542 
543     /**
544      * Returns the <code>i<code>th <code>ds:Object</code> child of the signature
545      * or null if no such <code>ds:Object</code> element exists.
546      *
547      * @param i
548      * @return the <code>i<code>th <code>ds:Object</code> child of the signature
549      * or null if no such <code>ds:Object</code> element exists.
550      */
551     public ObjectContainer getObjectItem(int i) {
552         Element objElem =
553             XMLUtils.selectDsNode(
554                 this.constructionElement.getFirstChild(), Constants._TAG_OBJECT, i
555             );
556 
557         try {
558             return new ObjectContainer(objElem, this.baseURI);
559         } catch (XMLSecurityException ex) {
560             return null;
561         }
562     }
563 
564     /**
565      * Returns the number of all <code>ds:Object</code> elements.
566      *
567      * @return the number of all <code>ds:Object</code> elements.
568      */
569     public int getObjectLength() {
570         return this.length(Constants.SignatureSpecNS, Constants._TAG_OBJECT);
571     }
572 
573     /**
574      * Digests all References in the SignedInfo, calculates the signature value
575      * and sets it in the SignatureValue Element.
576      *
577      * @param signingKey the {@link java.security.PrivateKey} or
578      * {@link javax.crypto.SecretKey} that is used to sign.
579      * @throws XMLSignatureException
580      */
581     public void sign(Key signingKey) throws XMLSignatureException {
582 
583         if (signingKey instanceof PublicKey) {
584             throw new IllegalArgumentException(
585                 I18n.translate("algorithms.operationOnlyVerification")
586             );
587         }
588 
589         try {
590             //Create a SignatureAlgorithm object
591             SignedInfo si = this.getSignedInfo();
592             SignatureAlgorithm sa = si.getSignatureAlgorithm();
593             OutputStream so = null;
594             try {
595                 // initialize SignatureAlgorithm for signing
596                 sa.initSign(signingKey);
597 
598                 // generate digest values for all References in this SignedInfo
599                 si.generateDigestValues();
600                 so = new UnsyncBufferedOutputStream(new SignerOutputStream(sa));
601                 // get the canonicalized bytes from SignedInfo
602                 si.signInOctetStream(so);
603             } catch (XMLSecurityException ex) {
604                 throw ex;
605             } finally {
606                 if (so != null) {
607                     try {
608                         so.close();
609                     } catch (IOException ex) {
610                         if (log.isLoggable(java.util.logging.Level.FINE)) {
611                             log.log(java.util.logging.Level.FINE, ex.getMessage(), ex);
612                         }
613                     }
614                 }
615             }
616 
617             // set them on the SignatureValue element
618             this.setSignatureValueElement(sa.sign());
619         } catch (XMLSignatureException ex) {
620             throw ex;
621         } catch (CanonicalizationException ex) {
622             throw new XMLSignatureException("empty", ex);
623         } catch (InvalidCanonicalizerException ex) {
624             throw new XMLSignatureException("empty", ex);
625         } catch (XMLSecurityException ex) {
626             throw new XMLSignatureException("empty", ex);
627         }
628     }
629 
630     /**
631      * Adds a {@link ResourceResolver} to enable the retrieval of resources.
632      *
633      * @param resolver
634      */
635     public void addResourceResolver(ResourceResolver resolver) {
636         this.getSignedInfo().addResourceResolver(resolver);
637     }
638 
639     /**
640      * Adds a {@link ResourceResolverSpi} to enable the retrieval of resources.
641      *
642      * @param resolver
643      */
644     public void addResourceResolver(ResourceResolverSpi resolver) {
645         this.getSignedInfo().addResourceResolver(resolver);
646     }
647 
648     /**
649      * Extracts the public key from the certificate and verifies if the signature
650      * is valid by re-digesting all References, comparing those against the
651      * stored DigestValues and then checking to see if the Signatures match on
652      * the SignedInfo.
653      *
654      * @param cert Certificate that contains the public key part of the keypair
655      * that was used to sign.
656      * @return true if the signature is valid, false otherwise
657      * @throws XMLSignatureException
658      */
659     public boolean checkSignatureValue(X509Certificate cert)
660         throws XMLSignatureException {
661         // see if cert is null
662         if (cert != null) {
663             // check the values with the public key from the cert
664             return this.checkSignatureValue(cert.getPublicKey());
665         }
666 
667         Object exArgs[] = { "Didn't get a certificate" };
668         throw new XMLSignatureException("empty", exArgs);
669     }
670 
671     /**
672      * Verifies if the signature is valid by redigesting all References,
673      * comparing those against the stored DigestValues and then checking to see
674      * if the Signatures match on the SignedInfo.
675      *
676      * @param pk {@link java.security.PublicKey} part of the keypair or
677      * {@link javax.crypto.SecretKey} that was used to sign
678      * @return true if the signature is valid, false otherwise
679      * @throws XMLSignatureException
680      */
681     public boolean checkSignatureValue(Key pk) throws XMLSignatureException {
682         //COMMENT: pk suggests it can only be a public key?
683         //check to see if the key is not null
684         if (pk == null) {
685             Object exArgs[] = { "Didn't get a key" };
686             throw new XMLSignatureException("empty", exArgs);
687         }
688         // all references inside the signedinfo need to be dereferenced and
689         // digested again to see if the outcome matches the stored value in the
690         // SignedInfo.
691         // If followManifestsDuringValidation is true it will do the same for
692         // References inside a Manifest.
693         try {
694             SignedInfo si = this.getSignedInfo();
695             //create a SignatureAlgorithms from the SignatureMethod inside
696             //SignedInfo. This is used to validate the signature.
697             SignatureAlgorithm sa = si.getSignatureAlgorithm();
698             if (log.isLoggable(java.util.logging.Level.FINE)) {
699                 log.log(java.util.logging.Level.FINE, "signatureMethodURI = " + sa.getAlgorithmURI());
700                 log.log(java.util.logging.Level.FINE, "jceSigAlgorithm    = " + sa.getJCEAlgorithmString());
701                 log.log(java.util.logging.Level.FINE, "jceSigProvider     = " + sa.getJCEProviderName());
702                 log.log(java.util.logging.Level.FINE, "PublicKey = " + pk);
703             }
704             byte sigBytes[] = null;
705             try {
706                 sa.initVerify(pk);
707 
708                 // Get the canonicalized (normalized) SignedInfo
709                 SignerOutputStream so = new SignerOutputStream(sa);
710                 OutputStream bos = new UnsyncBufferedOutputStream(so);
711 
712                 si.signInOctetStream(bos);
713                 bos.close();
714                 // retrieve the byte[] from the stored signature
715                 sigBytes = this.getSignatureValue();
716             } catch (IOException ex) {
717                 if (log.isLoggable(java.util.logging.Level.FINE)) {
718                     log.log(java.util.logging.Level.FINE, ex.getMessage(), ex);
719                 }
720                 // Impossible...
721             } catch (XMLSecurityException ex) {
722                 throw ex;
723             }
724 
725             // have SignatureAlgorithm sign the input bytes and compare them to
726             // the bytes that were stored in the signature.
727             if (!sa.verify(sigBytes)) {
728                 log.log(java.util.logging.Level.WARNING, "Signature verification failed.");
729                 return false;
730             }
731 
732             return si.verify(this.followManifestsDuringValidation);
733         } catch (XMLSignatureException ex) {
734             throw ex;
735         } catch (XMLSecurityException ex) {
736             throw new XMLSignatureException("empty", ex);
737         }
738     }
739 
740     /**
741      * Add a Reference with full parameters to this Signature
742      *
743      * @param referenceURI URI of the resource to be signed. Can be null in
744      * which case the dereferencing is application specific. Can be "" in which
745      * it's the parent node (or parent document?). There can only be one "" in
746      * each signature.
747      * @param trans Optional list of transformations to be done before digesting
748      * @param digestURI Mandatory URI of the digesting algorithm to use.
749      * @param referenceId Optional id attribute for this Reference
750      * @param referenceType Optional mimetype for the URI
751      * @throws XMLSignatureException
752      */
753     public void addDocument(
754         String referenceURI,
755         Transforms trans,
756         String digestURI,
757         String referenceId,
758         String referenceType
759     ) throws XMLSignatureException {
760         this.signedInfo.addDocument(
761             this.baseURI, referenceURI, trans, digestURI, referenceId, referenceType
762         );
763     }
764 
765     /**
766      * This method is a proxy method for the {@link Manifest#addDocument} method.
767      *
768      * @param referenceURI URI according to the XML Signature specification.
769      * @param trans List of transformations to be applied.
770      * @param digestURI URI of the digest algorithm to be used.
771      * @see Manifest#addDocument
772      * @throws XMLSignatureException
773      */
774     public void addDocument(
775         String referenceURI,
776         Transforms trans,
777         String digestURI
778     ) throws XMLSignatureException {
779         this.signedInfo.addDocument(this.baseURI, referenceURI, trans, digestURI, null, null);
780     }
781 
782     /**
783      * Adds a Reference with just the URI and the transforms. This used the
784      * SHA1 algorithm as a default digest algorithm.
785      *
786      * @param referenceURI URI according to the XML Signature specification.
787      * @param trans List of transformations to be applied.
788      * @throws XMLSignatureException
789      */
790     public void addDocument(String referenceURI, Transforms trans)
791         throws XMLSignatureException {
792         this.signedInfo.addDocument(
793             this.baseURI, referenceURI, trans, Constants.ALGO_ID_DIGEST_SHA1, null, null
794         );
795     }
796 
797     /**
798      * Add a Reference with just this URI. It uses SHA1 by default as the digest
799      * algorithm
800      *
801      * @param referenceURI URI according to the XML Signature specification.
802      * @throws XMLSignatureException
803      */
804     public void addDocument(String referenceURI) throws XMLSignatureException {
805         this.signedInfo.addDocument(
806             this.baseURI, referenceURI, null, Constants.ALGO_ID_DIGEST_SHA1, null, null
807         );
808     }
809 
810     /**
811      * Add an X509 Certificate to the KeyInfo. This will include the whole cert
812      * inside X509Data/X509Certificate tags.
813      *
814      * @param cert Certificate to be included. This should be the certificate of
815      * the key that was used to sign.
816      * @throws XMLSecurityException
817      */
818     public void addKeyInfo(X509Certificate cert) throws XMLSecurityException {
819         X509Data x509data = new X509Data(this.doc);
820 
821         x509data.addCertificate(cert);
822         this.getKeyInfo().add(x509data);
823     }
824 
825     /**
826      * Add this public key to the KeyInfo. This will include the complete key in
827      * the KeyInfo structure.
828      *
829      * @param pk
830      */
831     public void addKeyInfo(PublicKey pk) {
832         this.getKeyInfo().add(pk);
833     }
834 
835     /**
836      * Proxy method for {@link SignedInfo#createSecretKey(byte[])}. If you want
837      * to create a MAC, this method helps you to obtain the
838      * {@link javax.crypto.SecretKey} from octets.
839      *
840      * @param secretKeyBytes
841      * @return the secret key created.
842      * @see SignedInfo#createSecretKey(byte[])
843      */
844     public SecretKey createSecretKey(byte[] secretKeyBytes) {
845         return this.getSignedInfo().createSecretKey(secretKeyBytes);
846     }
847 
848     /**
849      * Signal whether Manifest should be automatically validated.
850      * Checking the digests in References in a Signature are mandatory, but for
851      * References inside a Manifest it is application specific. This boolean is
852      * to indicate that the References inside Manifests should be validated.
853      *
854      * @param followManifests
855      * @see <a href="http://www.w3.org/TR/xmldsig-core/#sec-CoreValidation">
856      * Core validation section in the XML Signature Rec.</a>
857      */
858     public void setFollowNestedManifests(boolean followManifests) {
859         this.followManifestsDuringValidation = followManifests;
860     }
861 
862     /**
863      * Get the local name of this element
864      *
865      * @return Constants._TAG_SIGNATURE
866      */
867     public String getBaseLocalName() {
868         return Constants._TAG_SIGNATURE;
869     }
870 }