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.ByteArrayInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 
30 import javax.crypto.SecretKey;
31 import javax.crypto.spec.SecretKeySpec;
32 import javax.xml.parsers.ParserConfigurationException;
33 
34 import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;
35 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
36 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
37 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
38 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
39 import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
40 import com.sun.org.apache.xml.internal.security.utils.Constants;
41 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.Node;
45 import org.xml.sax.SAXException;
46 
47 /**
48  * Handles {@code <ds:SignedInfo>} elements
49  * This {@code SignedInfo} element includes the canonicalization algorithm,
50  * a signature algorithm, and one or more references.
51  *
52  */
53 public class SignedInfo extends Manifest {
54 
55     /** Field signatureAlgorithm */
56     private SignatureAlgorithm signatureAlgorithm;
57 
58     /** Field c14nizedBytes           */
59     private byte[] c14nizedBytes;
60 
61     private Element c14nMethod;
62     private Element signatureMethod;
63 
64     /**
65      * Overwrites {@link Manifest#addDocument} because it creates another
66      * Element.
67      *
68      * @param doc the {@link Document} in which {@code XMLsignature} will
69      *    be placed
70      * @throws XMLSecurityException
71      */
SignedInfo(Document doc)72     public SignedInfo(Document doc) throws XMLSecurityException {
73         this(doc, XMLSignature.ALGO_ID_SIGNATURE_DSA,
74              Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
75     }
76 
77     /**
78      * Constructs {@link SignedInfo} using given Canonicalization algorithm and
79      * Signature algorithm.
80      *
81      * @param doc {@code SignedInfo} is placed in this document
82      * @param signatureMethodURI URI representation of the Digest and
83      *    Signature algorithm
84      * @param canonicalizationMethodURI URI representation of the
85      *    Canonicalization method
86      * @throws XMLSecurityException
87      */
SignedInfo( Document doc, String signatureMethodURI, String canonicalizationMethodURI )88     public SignedInfo(
89         Document doc, String signatureMethodURI, String canonicalizationMethodURI
90     ) throws XMLSecurityException {
91         this(doc, signatureMethodURI, 0, canonicalizationMethodURI);
92     }
93 
94     /**
95      * Constructor SignedInfo
96      *
97      * @param doc {@code SignedInfo} is placed in this document
98      * @param signatureMethodURI URI representation of the Digest and
99      *    Signature algorithm
100      * @param hMACOutputLength
101      * @param canonicalizationMethodURI URI representation of the
102      *    Canonicalization method
103      * @throws XMLSecurityException
104      */
SignedInfo( Document doc, String signatureMethodURI, int hMACOutputLength, String canonicalizationMethodURI )105     public SignedInfo(
106         Document doc, String signatureMethodURI,
107         int hMACOutputLength, String canonicalizationMethodURI
108     ) throws XMLSecurityException {
109         super(doc);
110 
111         c14nMethod =
112             XMLUtils.createElementInSignatureSpace(getDocument(), Constants._TAG_CANONICALIZATIONMETHOD);
113 
114         c14nMethod.setAttributeNS(null, Constants._ATT_ALGORITHM, canonicalizationMethodURI);
115         appendSelf(c14nMethod);
116         addReturnToSelf();
117 
118         if (hMACOutputLength > 0) {
119             this.signatureAlgorithm =
120                 new SignatureAlgorithm(getDocument(), signatureMethodURI, hMACOutputLength);
121         } else {
122             this.signatureAlgorithm = new SignatureAlgorithm(getDocument(), signatureMethodURI);
123         }
124 
125         signatureMethod = this.signatureAlgorithm.getElement();
126         appendSelf(signatureMethod);
127         addReturnToSelf();
128     }
129 
130     /**
131      * @param doc
132      * @param signatureMethodElem
133      * @param canonicalizationMethodElem
134      * @throws XMLSecurityException
135      */
SignedInfo( Document doc, Element signatureMethodElem, Element canonicalizationMethodElem )136     public SignedInfo(
137         Document doc, Element signatureMethodElem, Element canonicalizationMethodElem
138     ) throws XMLSecurityException {
139         super(doc);
140         // Check this?
141         this.c14nMethod = canonicalizationMethodElem;
142         appendSelf(c14nMethod);
143         addReturnToSelf();
144 
145         this.signatureAlgorithm =
146             new SignatureAlgorithm(signatureMethodElem, null);
147 
148         signatureMethod = this.signatureAlgorithm.getElement();
149         appendSelf(signatureMethod);
150 
151         addReturnToSelf();
152     }
153 
154     /**
155      * Build a {@link SignedInfo} from an {@link Element}
156      *
157      * @param element {@code SignedInfo}
158      * @param baseURI the URI of the resource where the XML instance was stored
159      * @throws XMLSecurityException
160      * @see <A HREF="http://lists.w3.org/Archives/Public/w3c-ietf-xmldsig/2001OctDec/0033.html">
161      * Question</A>
162      * @see <A HREF="http://lists.w3.org/Archives/Public/w3c-ietf-xmldsig/2001OctDec/0054.html">
163      * Answer</A>
164      */
SignedInfo(Element element, String baseURI)165     public SignedInfo(Element element, String baseURI) throws XMLSecurityException {
166         this(element, baseURI, true);
167     }
168 
169     /**
170      * Build a {@link SignedInfo} from an {@link Element}
171      *
172      * @param element {@code SignedInfo}
173      * @param baseURI the URI of the resource where the XML instance was stored
174      * @param secureValidation whether secure validation is enabled or not
175      * @throws XMLSecurityException
176      * @see <A HREF="http://lists.w3.org/Archives/Public/w3c-ietf-xmldsig/2001OctDec/0033.html">
177      * Question</A>
178      * @see <A HREF="http://lists.w3.org/Archives/Public/w3c-ietf-xmldsig/2001OctDec/0054.html">
179      * Answer</A>
180      */
SignedInfo( Element element, String baseURI, boolean secureValidation )181     public SignedInfo(
182         Element element, String baseURI, boolean secureValidation
183     ) throws XMLSecurityException {
184         // Parse the Reference children and Id attribute in the Manifest
185         super(reparseSignedInfoElem(element, secureValidation), baseURI, secureValidation);
186 
187         c14nMethod = XMLUtils.getNextElement(element.getFirstChild());
188         signatureMethod = XMLUtils.getNextElement(c14nMethod.getNextSibling());
189         this.signatureAlgorithm =
190             new SignatureAlgorithm(signatureMethod, this.getBaseURI(), secureValidation);
191     }
192 
reparseSignedInfoElem(Element element, boolean secureValidation)193     private static Element reparseSignedInfoElem(Element element, boolean secureValidation)
194         throws XMLSecurityException {
195         /*
196          * If a custom canonicalizationMethod is used, canonicalize
197          * ds:SignedInfo, reparse it into a new document
198          * and replace the original not-canonicalized ds:SignedInfo by
199          * the re-parsed canonicalized one.
200          */
201         Element c14nMethod = XMLUtils.getNextElement(element.getFirstChild());
202         String c14nMethodURI =
203             c14nMethod.getAttributeNS(null, Constants._ATT_ALGORITHM);
204         if (!(c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS) ||
205             c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS) ||
206             c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS) ||
207             c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS) ||
208             c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS) ||
209             c14nMethodURI.equals(Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS))) {
210             // the c14n is not a secure one and can rewrite the URIs or like
211             // so reparse the SignedInfo to be sure
212             try {
213                 Canonicalizer c14nizer =
214                     Canonicalizer.getInstance(c14nMethodURI);
215                 c14nizer.setSecureValidation(secureValidation);
216 
217                 byte[] c14nizedBytes = c14nizer.canonicalizeSubtree(element);
218                 javax.xml.parsers.DocumentBuilder db =
219                     XMLUtils.createDocumentBuilder(false, secureValidation);
220                 try (InputStream is = new ByteArrayInputStream(c14nizedBytes)) {
221                     Document newdoc = db.parse(is);
222                     Node imported = element.getOwnerDocument().importNode(
223                             newdoc.getDocumentElement(), true);
224                     element.getParentNode().replaceChild(imported, element);
225                     return (Element) imported;
226                 }
227             } catch (ParserConfigurationException ex) {
228                 throw new XMLSecurityException(ex);
229             } catch (IOException ex) {
230                 throw new XMLSecurityException(ex);
231             } catch (SAXException ex) {
232                 throw new XMLSecurityException(ex);
233             }
234         }
235         return element;
236     }
237 
238     /**
239      * Tests core validation process
240      *
241      * @return true if verification was successful
242      * @throws MissingResourceFailureException
243      * @throws XMLSecurityException
244      */
verify()245     public boolean verify()
246         throws MissingResourceFailureException, XMLSecurityException {
247         return super.verifyReferences(false);
248     }
249 
250     /**
251      * Tests core validation process
252      *
253      * @param followManifests defines whether the verification process has to verify referenced {@code ds:Manifest}s, too
254      * @return true if verification was successful
255      * @throws MissingResourceFailureException
256      * @throws XMLSecurityException
257      */
verify(boolean followManifests)258     public boolean verify(boolean followManifests)
259         throws MissingResourceFailureException, XMLSecurityException {
260         return super.verifyReferences(followManifests);
261     }
262 
263     /**
264      * Returns getCanonicalizedOctetStream
265      *
266      * @return the canonicalization result octet stream of {@code SignedInfo} element
267      * @throws CanonicalizationException
268      * @throws InvalidCanonicalizerException
269      * @throws XMLSecurityException
270      */
getCanonicalizedOctetStream()271     public byte[] getCanonicalizedOctetStream()
272         throws CanonicalizationException, InvalidCanonicalizerException, XMLSecurityException {
273         if (this.c14nizedBytes == null) {
274             Canonicalizer c14nizer =
275                 Canonicalizer.getInstance(this.getCanonicalizationMethodURI());
276             c14nizer.setSecureValidation(isSecureValidation());
277 
278             String inclusiveNamespaces = this.getInclusiveNamespaces();
279             if (inclusiveNamespaces == null) {
280                 this.c14nizedBytes = c14nizer.canonicalizeSubtree(getElement());
281             } else {
282                 this.c14nizedBytes = c14nizer.canonicalizeSubtree(getElement(), inclusiveNamespaces);
283             }
284         }
285 
286         // make defensive copy
287         return this.c14nizedBytes.clone();
288     }
289 
290     /**
291      * Output the C14n stream to the given OutputStream.
292      * @param os
293      * @throws CanonicalizationException
294      * @throws InvalidCanonicalizerException
295      * @throws XMLSecurityException
296      */
signInOctetStream(OutputStream os)297     public void signInOctetStream(OutputStream os)
298         throws CanonicalizationException, InvalidCanonicalizerException, XMLSecurityException {
299         if (this.c14nizedBytes == null) {
300             Canonicalizer c14nizer =
301                 Canonicalizer.getInstance(this.getCanonicalizationMethodURI());
302             c14nizer.setSecureValidation(isSecureValidation());
303             c14nizer.setWriter(os);
304             String inclusiveNamespaces = this.getInclusiveNamespaces();
305 
306             if (inclusiveNamespaces == null) {
307                 c14nizer.canonicalizeSubtree(getElement());
308             } else {
309                 c14nizer.canonicalizeSubtree(getElement(), inclusiveNamespaces);
310             }
311         } else {
312             try {
313                 os.write(this.c14nizedBytes);
314             } catch (IOException e) {
315                 throw new RuntimeException(e);
316             }
317         }
318     }
319 
320     /**
321      * Returns the Canonicalization method URI
322      *
323      * @return the Canonicalization method URI
324      */
getCanonicalizationMethodURI()325     public String getCanonicalizationMethodURI() {
326         return c14nMethod.getAttributeNS(null, Constants._ATT_ALGORITHM);
327     }
328 
329     /**
330      * Returns the Signature method URI
331      *
332      * @return the Signature method URI
333      */
getSignatureMethodURI()334     public String getSignatureMethodURI() {
335         Element signatureElement = this.getSignatureMethodElement();
336 
337         if (signatureElement != null) {
338             return signatureElement.getAttributeNS(null, Constants._ATT_ALGORITHM);
339         }
340 
341         return null;
342     }
343 
344     /**
345      * Method getSignatureMethodElement
346      * @return returns the SignatureMethod Element
347      *
348      */
getSignatureMethodElement()349     public Element getSignatureMethodElement() {
350         return signatureMethod;
351     }
352 
353     /**
354      * Creates a SecretKey for the appropriate Mac algorithm based on a
355      * byte[] array password.
356      *
357      * @param secretKeyBytes
358      * @return the secret key for the SignedInfo element.
359      */
createSecretKey(byte[] secretKeyBytes)360     public SecretKey createSecretKey(byte[] secretKeyBytes) {
361         return new SecretKeySpec(secretKeyBytes, this.signatureAlgorithm.getJCEAlgorithmString());
362     }
363 
getSignatureAlgorithm()364     public SignatureAlgorithm getSignatureAlgorithm() {
365         return signatureAlgorithm;
366     }
367 
368     /**
369      * Method getBaseLocalName
370      * {@inheritDoc}
371      *
372      */
getBaseLocalName()373     public String getBaseLocalName() {
374         return Constants._TAG_SIGNEDINFO;
375     }
376 
getInclusiveNamespaces()377     public String getInclusiveNamespaces() {
378         String c14nMethodURI = getCanonicalizationMethodURI();
379         if (!(c14nMethodURI.equals("http://www.w3.org/2001/10/xml-exc-c14n#") ||
380             c14nMethodURI.equals("http://www.w3.org/2001/10/xml-exc-c14n#WithComments"))) {
381             return null;
382         }
383 
384         Element inclusiveElement = XMLUtils.getNextElement(c14nMethod.getFirstChild());
385 
386         if (inclusiveElement != null) {
387             try {
388                 String inclusiveNamespaces =
389                     new InclusiveNamespaces(
390                         inclusiveElement,
391                         InclusiveNamespaces.ExclusiveCanonicalizationNamespace
392                     ).getInclusiveNamespaces();
393                 return inclusiveNamespaces;
394             } catch (XMLSecurityException e) {
395                 return null;
396             }
397         }
398         return null;
399     }
400 }
401