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