001: /*
002: * $Id: SignatureHeaderBlock.java,v 1.4 2007/01/08 09:28:47 ashutoshshahi Exp $
003: */
004:
005: /*
006: * The contents of this file are subject to the terms
007: * of the Common Development and Distribution License
008: * (the License). You may not use this file except in
009: * compliance with the License.
010: *
011: * You can obtain a copy of the license at
012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
013: * See the License for the specific language governing
014: * permissions and limitations under the License.
015: *
016: * When distributing Covered Code, include this CDDL
017: * Header Notice in each file and include the License file
018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
019: * If applicable, add the following below the CDDL Header,
020: * with the fields enclosed by brackets [] replaced by
021: * you own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
025: */
026:
027: package com.sun.xml.wss.core;
028:
029: import java.security.Key;
030: import java.security.cert.X509Certificate;
031: import java.util.logging.Level;
032: import java.util.logging.Logger;
033:
034: import javax.xml.soap.SOAPElement;
035:
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038:
039: import com.sun.org.apache.xml.internal.security.utils.ElementProxy;
040: import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
041: import com.sun.org.apache.xml.internal.security.signature.SignedInfo;
042: import com.sun.org.apache.xml.internal.security.transforms.Transforms;
043: import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
044: import com.sun.org.apache.xml.internal.security.signature.ObjectContainer;
045: import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
046: import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
047: import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
048: import com.sun.xml.wss.logging.LogDomainConstants;
049: import com.sun.xml.wss.impl.MessageConstants;
050:
051: import com.sun.xml.wss.XWSSecurityException;
052: import com.sun.xml.wss.impl.misc.SecurityHeaderBlockImpl;
053:
054: /**
055: <element name="Signature" type="ds:SignatureType"/>
056: <complexType name="SignatureType">
057: <sequence>
058: <element ref="ds:SignedInfo"/>
059: <element ref="ds:SignatureValue"/>
060: <element ref="ds:KeyInfo" minOccurs="0"/>
061: <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
062: </sequence>
063: <attribute name="Id" type="ID" use="optional"/>
064: </complexType>
065: */
066: public class SignatureHeaderBlock extends SecurityHeaderBlockImpl {
067:
068: public static final String SignatureSpecNS = MessageConstants.DSIG_NS;
069:
070: public static final String SignatureSpecNSprefix = MessageConstants.DSIG_PREFIX;
071:
072: public static final String TAG_SIGNATURE = "Signature";
073:
074: // delegate ds:Signature member from XML DSIG
075: XMLSignature delegateSignature = null;
076:
077: boolean dirty = false;
078:
079: private static Logger log = Logger.getLogger(
080: LogDomainConstants.WSS_API_DOMAIN,
081: LogDomainConstants.WSS_API_DOMAIN_BUNDLE);
082:
083: /**
084: * baseURI URI to be used as context for all relative URIs.
085: * Accepted by all Apache XMLSIG elements
086: */
087: String baseURI = null;
088:
089: /**
090: * The Owner Document of this Signature
091: */
092: private Document document = null;
093:
094: /**
095: * parse and create the Signature element
096: * @param elem the element representing an XML Signature
097: * NOTE : this constructor assumes a fully initialized XML Signature
098: * No modifications are allowed on the signature, We can only get existing
099: * values. For example appendObject() would throw an Exception. If
100: * a KeyInfo was not present in the signature, then calling getKeyInfo()
101: * will not append a KeyInfo child to the signature.
102: */
103: public SignatureHeaderBlock(SOAPElement elem)
104: throws XWSSecurityException {
105: super (elem);
106: try {
107: this .document = elem.getOwnerDocument();
108: delegateSignature = new XMLSignature(elem, null);
109: } catch (Exception e) {
110: // add log here
111: log.log(Level.SEVERE,
112: "WSS0322.exception.creating.signatureblock", e);
113: throw new XWSSecurityException(e);
114: }
115: }
116:
117: /**
118: * constructor that takes Apache Signature
119: * @param signature the XMLSignature from XML DSIG
120: * NOTE : No modifications are allowed on the signature,
121: * if a SIGN operation has already been performed on the argument
122: * signature. We can only get existing values.
123: * For example appendObject() would throw an Exception. If
124: * a KeyInfo was not present in the signature, then calling getKeyInfo()
125: * will not append a KeyInfo child to the signature.
126: */
127: public SignatureHeaderBlock(XMLSignature signature)
128: throws XWSSecurityException {
129: this .document = signature.getDocument();
130: delegateSignature = signature;
131: dirty = true;
132: setSOAPElement(getAsSoapElement());
133: }
134:
135: /**
136: * This creates a new <CODE>ds:Signature</CODE> Element and adds an empty
137: * <CODE>ds:SignedInfo</CODE>.
138: * The <code>ds:SignedInfo</code> is initialized with the specified
139: * Signature algorithm and Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS
140: * which is RECOMMENDED by the spec. This method's main use is for creating
141: * a new signature.
142: *
143: * @param doc The OwnerDocument of signature
144: * @param signatureMethodURI signature algorithm to use.
145: * @throws XWSSecurityException
146: */
147: public SignatureHeaderBlock(Document doc, String signatureMethodURI)
148: throws XWSSecurityException {
149: try {
150: this .document = doc;
151: delegateSignature = new XMLSignature(doc, null,
152: signatureMethodURI,
153: Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
154: dirty = true;
155: setSOAPElement(getAsSoapElement());
156: } catch (XMLSecurityException e) {
157: log.log(Level.SEVERE,
158: "WSS0322.exception.creating.signatureblock", e);
159: throw new XWSSecurityException(e);
160: }
161: }
162:
163: /**
164: * return the Apache XML Signature corresponding to this Block
165: * @return the XMLSignature
166: */
167: public XMLSignature getSignature() {
168: return delegateSignature;
169: }
170:
171: /**
172: * Digests all References in the SignedInfo, calculates the signature
173: * value and sets it in the SignatureValue Element.
174: *
175: * @param signingKey the {@link java.security.PrivateKey} or
176: * {@link javax.crypto.SecretKey} that is used to sign.
177: * @throws XWSSecurityException
178: */
179:
180: public void sign(Key signingKey) throws XWSSecurityException {
181: try {
182: delegateSignature.sign(signingKey);
183: dirty = true;
184: } catch (XMLSignatureException e) {
185: log.log(Level.SEVERE, "WSS0323.exception.while.signing", e);
186: throw new XWSSecurityException(e);
187: }
188: }
189:
190: /**
191: * Returns the completely parsed <code>SignedInfo</code> object.
192: *
193: * @return the SignedInfo as a SOAPElement
194: */
195: public SOAPElement getSignedInfo() throws XWSSecurityException {
196: return convertToSoapElement(delegateSignature.getSignedInfo());
197: }
198:
199: public SignedInfo getDSSignedInfo() {
200: return delegateSignature.getSignedInfo();
201: }
202:
203: /**
204: * Returns the KeyInfo child.
205: *
206: * @return the KeyInfo object
207: */
208: public SOAPElement getKeyInfo() throws XWSSecurityException {
209: return convertToSoapElement(delegateSignature.getKeyInfo());
210: }
211:
212: /**
213: * Returns the KeyInfo as a HeaderBlock.
214: *
215: * @return the KeyInfoHeaderBlock object
216: */
217: public KeyInfoHeaderBlock getKeyInfoHeaderBlock()
218: throws XWSSecurityException {
219: return new KeyInfoHeaderBlock(delegateSignature.getKeyInfo());
220: }
221:
222: /**
223: * Method getSignatureValue
224: * @throws XWSSecurityException
225: */
226: public byte[] getSignatureValue() throws XWSSecurityException {
227: try {
228: return delegateSignature.getSignatureValue();
229: } catch (XMLSignatureException e) {
230: log.log(Level.SEVERE,
231: "WSS0324.exception.in.getting.signaturevalue", e);
232: throw new XWSSecurityException(e);
233: }
234: }
235:
236: /**
237: * Adds a Reference with just the URI and the transforms. This uses the
238: * SHA1 algorithm as a default digest algorithm.
239: *
240: * @param referenceURI URI according to the XML Signature specification.
241: * @param transforms List of transformations to be applied.
242: * @throws XWSSecurityException
243: */
244: public void addSignedInfoReference(String referenceURI,
245: Transforms transforms) throws XWSSecurityException {
246: try {
247: delegateSignature.addDocument(referenceURI, transforms);
248: dirty = true;
249: } catch (XMLSecurityException e) {
250: log.log(Level.SEVERE,
251: "WSS0325.exception.adding.reference.to.signedinfo",
252: e);
253: throw new XWSSecurityException(e);
254: }
255: }
256:
257: /**
258: * Adds a Reference with URI, transforms and Digest algorithm URI
259: *
260: * @param referenceURI URI according to the XML Signature specification.
261: * @param trans List of transformations to be applied.
262: * @param digestURI URI of the digest algorithm to be used.
263: * @throws XWSSecurityException
264: */
265: public void addSignedInfoReference(String referenceURI,
266: Transforms trans, String digestURI)
267: throws XWSSecurityException {
268: try {
269: delegateSignature.addDocument(referenceURI, trans,
270: digestURI);
271: dirty = true;
272: } catch (XMLSecurityException e) {
273: log.log(Level.SEVERE,
274: "WSS0325.exception.adding.reference.to.signedinfo",
275: e);
276: throw new XWSSecurityException(e);
277: }
278: }
279:
280: /**
281: * Add a Reference with full parameters to this Signature
282: *
283: * @param referenceURI URI of the resource to be signed.Can be null in which
284: * case the dereferencing is application specific. Can be "" in which it's
285: * the parent node (or parent document?). There can only be one "" in each
286: * signature.
287: * @param trans Optional list of transformations to be done before digesting
288: * @param digestURI Mandatory URI of the digesting algorithm to use.
289: * @param referenceId Optional id attribute for this Reference
290: * @param referenceType Optional mimetype for the URI
291: * @throws XWSSecurityException
292: */
293: public void addSignedInfoReference(String referenceURI,
294: Transforms trans, String digestURI, String referenceId,
295: String referenceType) throws XWSSecurityException {
296: try {
297: delegateSignature.addDocument(referenceURI, trans,
298: digestURI, referenceId, referenceType);
299: dirty = true;
300: } catch (XMLSecurityException e) {
301: log.log(Level.SEVERE,
302: "WSS0325.exception.adding.reference.to.signedinfo",
303: e);
304: throw new XWSSecurityException(e);
305: }
306: }
307:
308: /**
309: * Extracts the public key from the certificate and verifies if the
310: * signature is valid by re-digesting all References, comparing those
311: * against the stored DigestValues and then checking to see if the
312: * Signatures match on the SignedInfo.
313: *
314: * @param cert Certificate that contains the public key part of the keypair
315: * that was used to sign.
316: * @return true if the signature is valid, false otherwise
317: * @throws XWSSecurityException
318: */
319: public boolean checkSignatureValue(X509Certificate cert)
320: throws XWSSecurityException {
321: try {
322: return delegateSignature.checkSignatureValue(cert);
323: } catch (XMLSignatureException e) {
324: log.log(Level.SEVERE,
325: "WSS0326.exception.verifying.signature", e);
326: throw new XWSSecurityException(e);
327: }
328: }
329:
330: /**
331: * Verifies if the signature is valid by redigesting all References,
332: * comparing those against the stored DigestValues and then checking to see
333: * if the Signatures match on the SignedInfo.
334: *
335: * @param pk {@link java.security.PublicKey} part of the keypair or
336: * {@link javax.crypto.SecretKey} that was used to sign
337: * @return true if the signature is valid, false otherwise
338: * @throws XWSSecurityException
339: */
340: public boolean checkSignatureValue(Key pk)
341: throws XWSSecurityException {
342: try {
343: return delegateSignature.checkSignatureValue(pk);
344: } catch (XMLSignatureException e) {
345: log.log(Level.SEVERE,
346: "WSS0326.exception.verifying.signature", e);
347: throw new XWSSecurityException(e);
348: }
349: }
350:
351: /**
352: * Method appendObject.
353: */
354: public void appendObject(SOAPElement object)
355: throws XWSSecurityException {
356: try {
357: ObjectContainer objc = new ObjectContainer(object, null);
358: delegateSignature.appendObject(objc);
359: } catch (XMLSecurityException e) {
360: log.log(Level.SEVERE, "WSS0382.error.appending.object", e
361: .getMessage());
362: throw new XWSSecurityException(e);
363: }
364: }
365:
366: /**
367: * Returns the <code>index<code>th <code>ds:Object</code> child of the
368: * signature or null if no such <code>ds:Object</code> element exists.
369: *
370: * @param index
371: * @return the <code>index<code>th <code>ds:Object</code> child of the
372: * signature or null if no such <code>ds:Object</code> element exists.
373: * 1 is the lowest index (not 0)
374: */
375: public SOAPElement getObjectItem(int index)
376: throws XWSSecurityException {
377: return convertToSoapElement(delegateSignature
378: .getObjectItem(index));
379: }
380:
381: /**
382: * Returns the number of all <code>ds:Object</code> elements.
383: *
384: * @return the number of all <code>ds:Object</code> elements.
385: */
386: public int getObjectCount() {
387: return delegateSignature.getObjectLength();
388: }
389:
390: /**
391: * Method setId
392: */
393: public void setId(String id) {
394: delegateSignature.setId(id);
395: }
396:
397: /**
398: * Method getId
399: *
400: * @return the id
401: */
402: public String getId() {
403: return delegateSignature.getId();
404: }
405:
406: /**
407: * Method setBaseURI : BaseURI needed by Apache KeyInfo Ctor
408: * @param uri URI to be used as context for all relative URIs.
409: */
410: public void setBaseURI(String uri) {
411: baseURI = uri;
412: }
413:
414: /**
415: * Method to return the Signature as a SOAPElement
416: *
417: * @return SOAPElement
418: * @throws XWSSecurityException
419: * If owner soap document is not set.
420: * @see #setDocument(Document)
421: */
422: public SOAPElement getAsSoapElement() throws XWSSecurityException {
423: if (document == null) {
424: log.log(Level.SEVERE, "WSS0383.document.not.set");
425: throw new XWSSecurityException("Document not set");
426: }
427: if (dirty) {
428: setSOAPElement(convertToSoapElement(delegateSignature));
429: dirty = false;
430: }
431: return delegateElement;
432: }
433:
434: /**
435: * setDocument.
436: * @param doc The owner Document of this Signature
437: */
438: public void setDocument(Document doc) {
439: this .document = doc;
440: }
441:
442: /**
443: * This method should be called when changes are made inside an object
444: * through its reference obtained from any of the get methods of this
445: * class. As an example, if getKeyInfo() call is made and then changes are made
446: * inside the keyInfo, this method should be called to reflect changes
447: * when getAsSoapElement() is called finally.
448: */
449: public void saveChanges() {
450: dirty = true;
451: }
452:
453: /*
454: * Add resolver for this instance of XMLSignature
455: */
456: public void setApacheResourceResolver(ResourceResolverSpi resolver) {
457: this .delegateSignature.addResourceResolver(resolver);
458: }
459:
460: public static SecurityHeaderBlock fromSoapElement(
461: SOAPElement element) throws XWSSecurityException {
462: return SecurityHeaderBlockImpl.fromSoapElement(element,
463: SignatureHeaderBlock.class);
464: }
465:
466: private SOAPElement convertToSoapElement(ElementProxy proxy)
467: throws XWSSecurityException {
468: try {
469: Element elem = proxy.getElement();
470: if (elem instanceof SOAPElement) {
471: return (SOAPElement) elem;
472: } else {
473: return (SOAPElement) document.importNode(elem, true);
474: }
475: } catch (Exception e) {
476: log
477: .log(
478: Level.SEVERE,
479: "WSS0327.exception.converting.signature.tosoapelement",
480: e);
481: throw new XWSSecurityException(e);
482: }
483: }
484:
485: }
|