blob: 782ab984386a71082fa672df776426c2fc4b258d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25/*
26 * $Id: DOMSignedInfo.java,v 1.30 2005/09/23 20:14:07 mullan Exp $
27 */
28package org.jcp.xml.dsig.internal.dom;
29
30import javax.xml.crypto.*;
31import javax.xml.crypto.dom.DOMCryptoContext;
32import javax.xml.crypto.dsig.*;
33
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36import java.io.InputStream;
37import java.io.IOException;
38import java.io.InputStreamReader;
39import java.io.OutputStream;
40import java.util.*;
41import java.util.logging.Level;
42import java.util.logging.Logger;
43import org.w3c.dom.Document;
44import org.w3c.dom.Element;
45import org.w3c.dom.Node;
46
47import com.sun.org.apache.xml.internal.security.utils.Base64;
48import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream;
49import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
50
51/**
52 * DOM-based implementation of SignedInfo.
53 *
54 * @author Sean Mullan
55 */
56public final class DOMSignedInfo extends DOMStructure implements SignedInfo {
57
58 private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom");
59 private List references;
60 private CanonicalizationMethod canonicalizationMethod;
61 private SignatureMethod signatureMethod;
62 private String id;
63 private Document ownerDoc;
64 private Element localSiElem;
65 private InputStream canonData;
66
67 /**
68 * Creates a <code>DOMSignedInfo</code> from the specified parameters. Use
69 * this constructor when the <code>Id</code> is not specified.
70 *
71 * @param cm the canonicalization method
72 * @param sm the signature method
73 * @param references the list of references. The list is copied.
74 * @throws NullPointerException if
75 * <code>cm</code>, <code>sm</code>, or <code>references</code> is
76 * <code>null</code>
77 * @throws IllegalArgumentException if <code>references</code> is empty
78 * @throws ClassCastException if any of the references are not of
79 * type <code>Reference</code>
80 */
81 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm,
82 List references) {
83 if (cm == null || sm == null || references == null) {
84 throw new NullPointerException();
85 }
86 this.canonicalizationMethod = cm;
87 this.signatureMethod = sm;
88 this.references = Collections.unmodifiableList
89 (new ArrayList(references));
90 if (this.references.isEmpty()) {
91 throw new IllegalArgumentException("list of references must " +
92 "contain at least one entry");
93 }
94 for (int i = 0, size = this.references.size(); i < size; i++) {
95 Object obj = this.references.get(i);
96 if (!(obj instanceof Reference)) {
97 throw new ClassCastException("list of references contains " +
98 "an illegal type");
99 }
100 }
101 }
102
103 /**
104 * Creates a <code>DOMSignedInfo</code> from the specified parameters.
105 *
106 * @param cm the canonicalization method
107 * @param sm the signature method
108 * @param references the list of references. The list is copied.
109 * @param id an optional identifer that will allow this
110 * <code>SignedInfo</code> to be referenced by other signatures and
111 * objects
112 * @throws NullPointerException if <code>cm</code>, <code>sm</code>,
113 * or <code>references</code> is <code>null</code>
114 * @throws IllegalArgumentException if <code>references</code> is empty
115 * @throws ClassCastException if any of the references are not of
116 * type <code>Reference</code>
117 */
118 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm,
119 List references, String id) {
120 this(cm, sm, references);
121 this.id = id;
122 }
123
124 /**
125 * Creates a <code>DOMSignedInfo</code> from an element.
126 *
127 * @param siElem a SignedInfo element
128 */
129 public DOMSignedInfo(Element siElem, XMLCryptoContext context)
130 throws MarshalException {
131 localSiElem = siElem;
132 ownerDoc = siElem.getOwnerDocument();
133
134 // get Id attribute, if specified
135 id = DOMUtils.getAttributeValue(siElem, "Id");
136
137 // unmarshal CanonicalizationMethod
138 Element cmElem = DOMUtils.getFirstChildElement(siElem);
139 canonicalizationMethod = new DOMCanonicalizationMethod(cmElem, context);
140
141 // unmarshal SignatureMethod
142 Element smElem = DOMUtils.getNextSiblingElement(cmElem);
143 signatureMethod = DOMSignatureMethod.unmarshal(smElem);
144
145 // unmarshal References
146 ArrayList refList = new ArrayList(5);
147 Element refElem = DOMUtils.getNextSiblingElement(smElem);
148 while (refElem != null) {
149 refList.add(new DOMReference(refElem, context));
150 refElem = DOMUtils.getNextSiblingElement(refElem);
151 }
152 references = Collections.unmodifiableList(refList);
153 }
154
155 public CanonicalizationMethod getCanonicalizationMethod() {
156 return canonicalizationMethod;
157 }
158
159 public SignatureMethod getSignatureMethod() {
160 return signatureMethod;
161 }
162
163 public String getId() {
164 return id;
165 }
166
167 public List getReferences() {
168 return references;
169 }
170
171 public InputStream getCanonicalizedData() {
172 return canonData;
173 }
174
175 public void canonicalize(XMLCryptoContext context,ByteArrayOutputStream bos)
176 throws XMLSignatureException {
177
178 if (context == null) {
179 throw new NullPointerException("context cannot be null");
180 }
181
182 OutputStream os = new UnsyncBufferedOutputStream(bos);
183 try {
184 os.close();
185 } catch (IOException e) {
186 // Impossible
187 }
188
189 DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true);
190
191 OctetStreamData data = null;
192 try {
193 data = (OctetStreamData) ((DOMCanonicalizationMethod)
194 canonicalizationMethod).canonicalize(subTree, context, os);
195 } catch (TransformException te) {
196 throw new XMLSignatureException(te);
197 }
198
199 byte[] signedInfoBytes = bos.toByteArray();
200
201 // this whole block should only be done if logging is enabled
202 if (log.isLoggable(Level.FINE)) {
203 InputStreamReader isr = new InputStreamReader
204 (new ByteArrayInputStream(signedInfoBytes));
205 char[] siBytes = new char[signedInfoBytes.length];
206 try {
207 isr.read(siBytes);
208 } catch (IOException ioex) {} //ignore since this is logging code
209 log.log(Level.FINE, "Canonicalized SignedInfo:\n"
210 + new String(siBytes));
211 log.log(Level.FINE, "Data to be signed/verified:"
212 + Base64.encode(signedInfoBytes));
213 }
214
215 this.canonData = new ByteArrayInputStream(signedInfoBytes);
216 }
217
218 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
219 throws MarshalException {
220 ownerDoc = DOMUtils.getOwnerDocument(parent);
221
222 Element siElem = DOMUtils.createElement
223 (ownerDoc, "SignedInfo", XMLSignature.XMLNS, dsPrefix);
224
225 // create and append CanonicalizationMethod element
226 DOMCanonicalizationMethod dcm =
227 (DOMCanonicalizationMethod) canonicalizationMethod;
228 dcm.marshal(siElem, dsPrefix, context);
229
230 // create and append SignatureMethod element
231 ((DOMSignatureMethod) signatureMethod).marshal
232 (siElem, dsPrefix, context);
233
234 // create and append Reference elements
235 for (int i = 0, size = references.size(); i < size; i++) {
236 DOMReference reference = (DOMReference) references.get(i);
237 reference.marshal(siElem, dsPrefix, context);
238 }
239
240 // append Id attribute
241 DOMUtils.setAttributeID(siElem, "Id", id);
242
243 parent.appendChild(siElem);
244 localSiElem = siElem;
245 }
246
247 public boolean equals(Object o) {
248 if (this == o) {
249 return true;
250 }
251
252 if (!(o instanceof SignedInfo)) {
253 return false;
254 }
255 SignedInfo osi = (SignedInfo) o;
256
257 boolean idEqual = (id == null ? osi.getId() == null :
258 id.equals(osi.getId()));
259
260 return (canonicalizationMethod.equals(osi.getCanonicalizationMethod())
261 && signatureMethod.equals(osi.getSignatureMethod()) &&
262 references.equals(osi.getReferences()) && idEqual);
263 }
264}