25 import java.io.ByteArrayInputStream; |
25 import java.io.ByteArrayInputStream; |
26 import java.io.ByteArrayOutputStream; |
26 import java.io.ByteArrayOutputStream; |
27 import java.io.IOException; |
27 import java.io.IOException; |
28 import java.io.InputStream; |
28 import java.io.InputStream; |
29 import java.io.OutputStream; |
29 import java.io.OutputStream; |
|
30 import java.nio.charset.StandardCharsets; |
30 import java.util.ArrayList; |
31 import java.util.ArrayList; |
31 import java.util.LinkedHashSet; |
32 import java.util.LinkedHashSet; |
32 import java.util.List; |
33 import java.util.List; |
33 import java.util.Set; |
34 import java.util.Set; |
34 |
35 |
35 import javax.xml.XMLConstants; |
|
36 import javax.xml.parsers.DocumentBuilder; |
36 import javax.xml.parsers.DocumentBuilder; |
37 import javax.xml.parsers.DocumentBuilderFactory; |
|
38 import javax.xml.parsers.ParserConfigurationException; |
37 import javax.xml.parsers.ParserConfigurationException; |
39 |
38 |
40 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; |
39 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; |
|
40 import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_OmitComments; |
|
41 import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315OmitComments; |
41 import com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase; |
42 import com.sun.org.apache.xml.internal.security.c14n.implementations.CanonicalizerBase; |
42 import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer20010315OmitComments; |
|
43 import com.sun.org.apache.xml.internal.security.c14n.implementations.Canonicalizer11_OmitComments; |
|
44 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityRuntimeException; |
43 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityRuntimeException; |
45 import com.sun.org.apache.xml.internal.security.utils.JavaUtils; |
44 import com.sun.org.apache.xml.internal.security.utils.JavaUtils; |
46 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; |
45 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; |
47 import org.w3c.dom.Document; |
46 import org.w3c.dom.Document; |
48 import org.w3c.dom.Node; |
47 import org.w3c.dom.Node; |
49 import org.xml.sax.SAXException; |
48 import org.xml.sax.SAXException; |
50 |
49 |
51 /** |
50 /** |
52 * Class XMLSignatureInput |
51 * Class XMLSignatureInput |
53 * |
52 * |
54 * @author Christian Geuer-Pollmann |
|
55 * $todo$ check whether an XMLSignatureInput can be _both_, octet stream _and_ node set? |
53 * $todo$ check whether an XMLSignatureInput can be _both_, octet stream _and_ node set? |
56 */ |
54 */ |
57 public class XMLSignatureInput { |
55 public class XMLSignatureInput { |
58 /* |
56 /* |
59 * The XMLSignature Input can be either: |
57 * The XMLSignature Input can be either: |
66 |
64 |
67 /** |
65 /** |
68 * Some InputStreams do not support the {@link java.io.InputStream#reset} |
66 * Some InputStreams do not support the {@link java.io.InputStream#reset} |
69 * method, so we read it in completely and work on our Proxy. |
67 * method, so we read it in completely and work on our Proxy. |
70 */ |
68 */ |
71 private InputStream inputOctetStreamProxy = null; |
69 private InputStream inputOctetStreamProxy; |
72 /** |
70 /** |
73 * The original NodeSet for this XMLSignatureInput |
71 * The original NodeSet for this XMLSignatureInput |
74 */ |
72 */ |
75 private Set<Node> inputNodeSet = null; |
73 private Set<Node> inputNodeSet; |
76 /** |
74 /** |
77 * The original Element |
75 * The original Element |
78 */ |
76 */ |
79 private Node subNode = null; |
77 private Node subNode; |
80 /** |
78 /** |
81 * Exclude Node *for enveloped transformations* |
79 * Exclude Node *for enveloped transformations* |
82 */ |
80 */ |
83 private Node excludeNode = null; |
81 private Node excludeNode; |
84 /** |
82 /** |
85 * |
83 * |
86 */ |
84 */ |
87 private boolean excludeComments = false; |
85 private boolean excludeComments = false; |
88 |
86 |
89 private boolean isNodeSet = false; |
87 private boolean isNodeSet = false; |
90 /** |
88 /** |
91 * A cached bytes |
89 * A cached bytes |
92 */ |
90 */ |
93 private byte[] bytes = null; |
91 private byte[] bytes; |
|
92 private boolean secureValidation; |
94 |
93 |
95 /** |
94 /** |
96 * Some Transforms may require explicit MIME type, charset (IANA registered |
95 * Some Transforms may require explicit MIME type, charset (IANA registered |
97 * "character set"), or other such information concerning the data they are |
96 * "character set"), or other such information concerning the data they are |
98 * receiving from an earlier Transform or the source data, although no |
97 * receiving from an earlier Transform or the source data, although no |
99 * Transform algorithm specified in this document needs such explicit |
98 * Transform algorithm specified in this document needs such explicit |
100 * information. Such data characteristics are provided as parameters to the |
99 * information. Such data characteristics are provided as parameters to the |
101 * Transform algorithm and should be described in the specification for the |
100 * Transform algorithm and should be described in the specification for the |
102 * algorithm. |
101 * algorithm. |
103 */ |
102 */ |
104 private String mimeType = null; |
103 private String mimeType; |
105 |
104 |
106 /** |
105 /** |
107 * Field sourceURI |
106 * Field sourceURI |
108 */ |
107 */ |
109 private String sourceURI = null; |
108 private String sourceURI; |
110 |
109 |
111 /** |
110 /** |
112 * Node Filter list. |
111 * Node Filter list. |
113 */ |
112 */ |
114 private List<NodeFilter> nodeFilters = new ArrayList<NodeFilter>(); |
113 private List<NodeFilter> nodeFilters = new ArrayList<>(); |
115 |
114 |
116 private boolean needsToBeExpanded = false; |
115 private boolean needsToBeExpanded = false; |
117 private OutputStream outputStream = null; |
116 private OutputStream outputStream; |
118 |
117 |
119 private DocumentBuilderFactory dfactory; |
118 /** |
|
119 * Pre-calculated digest value of the object in base64. |
|
120 */ |
|
121 private String preCalculatedDigest; |
120 |
122 |
121 /** |
123 /** |
122 * Construct a XMLSignatureInput from an octet array. |
124 * Construct a XMLSignatureInput from an octet array. |
123 * <p> |
125 * <p> |
124 * This is a comfort method, which internally converts the byte[] array into |
126 * This is a comfort method, which internally converts the byte[] array into |
156 * |
158 * |
157 * @param inputNodeSet |
159 * @param inputNodeSet |
158 */ |
160 */ |
159 public XMLSignatureInput(Set<Node> inputNodeSet) { |
161 public XMLSignatureInput(Set<Node> inputNodeSet) { |
160 this.inputNodeSet = inputNodeSet; |
162 this.inputNodeSet = inputNodeSet; |
|
163 } |
|
164 |
|
165 /** |
|
166 * Construct a {@code XMLSignatureInput} from a known digest value in Base64. |
|
167 * This makes it possible to compare the element digest with the provided digest value. |
|
168 * @param preCalculatedDigest digest value in base64. |
|
169 */ |
|
170 public XMLSignatureInput(String preCalculatedDigest) { |
|
171 this.preCalculatedDigest = preCalculatedDigest; |
161 } |
172 } |
162 |
173 |
163 /** |
174 /** |
164 * Check if the structure needs to be expanded. |
175 * Check if the structure needs to be expanded. |
165 * @return true if so. |
176 * @return true if so. |
284 * Determines if the object has been set up with a Node set |
295 * Determines if the object has been set up with a Node set |
285 * |
296 * |
286 * @return true if the object has been set up with a Node set |
297 * @return true if the object has been set up with a Node set |
287 */ |
298 */ |
288 public boolean isNodeSet() { |
299 public boolean isNodeSet() { |
289 return ((inputOctetStreamProxy == null |
300 return inputOctetStreamProxy == null && inputNodeSet != null || isNodeSet; |
290 && inputNodeSet != null) || isNodeSet); |
|
291 } |
301 } |
292 |
302 |
293 /** |
303 /** |
294 * Determines if the object has been set up with an Element |
304 * Determines if the object has been set up with an Element |
295 * |
305 * |
296 * @return true if the object has been set up with an Element |
306 * @return true if the object has been set up with an Element |
297 */ |
307 */ |
298 public boolean isElement() { |
308 public boolean isElement() { |
299 return (inputOctetStreamProxy == null && subNode != null |
309 return inputOctetStreamProxy == null && subNode != null |
300 && inputNodeSet == null && !isNodeSet); |
310 && inputNodeSet == null && !isNodeSet; |
301 } |
311 } |
302 |
312 |
303 /** |
313 /** |
304 * Determines if the object has been set up with an octet stream |
314 * Determines if the object has been set up with an octet stream |
305 * |
315 * |
306 * @return true if the object has been set up with an octet stream |
316 * @return true if the object has been set up with an octet stream |
307 */ |
317 */ |
308 public boolean isOctetStream() { |
318 public boolean isOctetStream() { |
309 return ((inputOctetStreamProxy != null || bytes != null) |
319 return (inputOctetStreamProxy != null || bytes != null) |
310 && (inputNodeSet == null && subNode == null)); |
320 && inputNodeSet == null && subNode == null; |
311 } |
321 } |
312 |
322 |
313 /** |
323 /** |
314 * Determines if {@link #setOutputStream} has been called with a |
324 * Determines if {@link #setOutputStream} has been called with a |
315 * non-null OutputStream. |
325 * non-null OutputStream. |
325 * Determines if the object has been set up with a ByteArray |
335 * Determines if the object has been set up with a ByteArray |
326 * |
336 * |
327 * @return true is the object has been set up with an octet stream |
337 * @return true is the object has been set up with an octet stream |
328 */ |
338 */ |
329 public boolean isByteArray() { |
339 public boolean isByteArray() { |
330 return (bytes != null && (this.inputNodeSet == null && subNode == null)); |
340 return bytes != null && this.inputNodeSet == null && subNode == null; |
|
341 } |
|
342 |
|
343 /** |
|
344 * Determines if the object has been set up with a pre-calculated digest. |
|
345 * @return |
|
346 */ |
|
347 public boolean isPreCalculatedDigest() { |
|
348 return preCalculatedDigest != null; |
331 } |
349 } |
332 |
350 |
333 /** |
351 /** |
334 * Is the object correctly set up? |
352 * Is the object correctly set up? |
335 * |
353 * |
554 isNodeSet = b; |
572 isNodeSet = b; |
555 } |
573 } |
556 |
574 |
557 void convertToNodes() throws CanonicalizationException, |
575 void convertToNodes() throws CanonicalizationException, |
558 ParserConfigurationException, IOException, SAXException { |
576 ParserConfigurationException, IOException, SAXException { |
559 if (dfactory == null) { |
577 DocumentBuilder db = XMLUtils.createDocumentBuilder(false, secureValidation); |
560 dfactory = DocumentBuilderFactory.newInstance(); |
|
561 dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); |
|
562 dfactory.setValidating(false); |
|
563 dfactory.setNamespaceAware(true); |
|
564 } |
|
565 DocumentBuilder db = dfactory.newDocumentBuilder(); |
|
566 // select all nodes, also the comments. |
578 // select all nodes, also the comments. |
567 try { |
579 try { |
568 db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils.IgnoreAllErrorHandler()); |
580 db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils.IgnoreAllErrorHandler()); |
569 |
581 |
570 Document doc = db.parse(this.getOctetStream()); |
582 Document doc = db.parse(this.getOctetStream()); |
571 this.subNode = doc; |
583 this.subNode = doc; |
572 } catch (SAXException ex) { |
584 } catch (SAXException ex) { |
|
585 byte[] result = null; |
573 // if a not-wellformed nodeset exists, put a container around it... |
586 // if a not-wellformed nodeset exists, put a container around it... |
574 ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
587 try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { |
575 |
588 |
576 baos.write("<container>".getBytes("UTF-8")); |
589 baos.write("<container>".getBytes(StandardCharsets.UTF_8)); |
577 baos.write(this.getBytes()); |
590 baos.write(this.getBytes()); |
578 baos.write("</container>".getBytes("UTF-8")); |
591 baos.write("</container>".getBytes(StandardCharsets.UTF_8)); |
579 |
592 |
580 byte result[] = baos.toByteArray(); |
593 result = baos.toByteArray(); |
581 Document document = db.parse(new ByteArrayInputStream(result)); |
594 } |
582 this.subNode = document.getDocumentElement().getFirstChild().getFirstChild(); |
595 try (InputStream is = new ByteArrayInputStream(result)) { |
|
596 Document document = db.parse(is); |
|
597 this.subNode = document.getDocumentElement().getFirstChild().getFirstChild(); |
|
598 } |
583 } finally { |
599 } finally { |
584 if (this.inputOctetStreamProxy != null) { |
600 if (this.inputOctetStreamProxy != null) { |
585 this.inputOctetStreamProxy.close(); |
601 this.inputOctetStreamProxy.close(); |
586 } |
602 } |
587 this.inputOctetStreamProxy = null; |
603 this.inputOctetStreamProxy = null; |
588 this.bytes = null; |
604 this.bytes = null; |
589 } |
605 } |
590 } |
606 } |
591 |
607 |
|
608 public boolean isSecureValidation() { |
|
609 return secureValidation; |
|
610 } |
|
611 |
|
612 public void setSecureValidation(boolean secureValidation) { |
|
613 this.secureValidation = secureValidation; |
|
614 } |
|
615 |
|
616 public String getPreCalculatedDigest() { |
|
617 return preCalculatedDigest; |
|
618 } |
592 } |
619 } |