API Overview API Index Package Overview Direct link to this page
JDK 1.6
  org.jcp.xml.dsig.internal.dom. DOMXMLSignature View Javadoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557

/*
 * Portions copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
/*
 * ===========================================================================
 *
 * (C) Copyright IBM Corp. 2003 All Rights Reserved.
 *
 * ===========================================================================
 */
/*
 * $Id: DOMXMLSignature.java,v 1.42 2005/09/23 20:29:04 mullan Exp $
 */
package org.jcp.xml.dsig.internal.dom;

import javax.xml.crypto.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;

import java.io.*;
import java.security.InvalidKeyException;
import java.security.Key;
import java.util.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

/**
 * DOM-based implementation of XMLSignature.
 *
 * @author Sean Mullan
 * @author Joyce Leung
 */
public final class DOMXMLSignature extends DOMStructure 
    implements XMLSignature {

    private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom");
    private String id;
    private SignatureValue sv;
    private KeyInfo ki;
    private List objects;
    private SignedInfo si;
    private Document ownerDoc = null;
    private Element localSigElem = null;
    private Element sigElem = null;
    private boolean validationStatus;
    private boolean validated = false;
    private KeySelectorResult ksr;
    private HashMap signatureIdMap;

    static {
	com.sun.org.apache.xml.internal.security.Init.init();
    }
 
    /**
     * Creates a <code>DOMXMLSignature</code> from the specified components.
     *
     * @param si the <code>SignedInfo</code>
     * @param ki the <code>KeyInfo</code>, or <code>null</code> if not specified
     * @param objs a list of <code>XMLObject</code>s or <code>null</code>
     *  if not specified. The list is copied to protect against subsequent
     *  modification.
     * @param id an optional id (specify <code>null</code> to omit)
     * @param signatureValueId an optional id (specify <code>null</code> to
     *  omit)
     * @throws NullPointerException if <code>si</code> is <code>null</code>
     */
    public DOMXMLSignature(SignedInfo si, KeyInfo ki, List objs, String id, 
	String signatureValueId)
    {
        if (si == null) {
            throw new NullPointerException("signedInfo cannot be null");
        }
        this.si = si;
        this.id = id;
        this.sv = new DOMSignatureValue(signatureValueId);
        if (objs == null) {
            this.objects = Collections.EMPTY_LIST;
        } else {
            List objsCopy = new ArrayList(objs);
            for (int i = 0, size = objsCopy.size(); i < size; i++) {
                if (!(objsCopy.get(i) instanceof XMLObject)) {
                    throw new ClassCastException
                        ("objs["+i+"] is not an XMLObject");
                }
            }
            this.objects = Collections.unmodifiableList(objsCopy);
        }
        this.ki = ki;                
    }

    /**
     * Creates a <code>DOMXMLSignature</code> from XML.
     *
     * @param sigElem Signature element
     * @throws MarshalException if XMLSignature cannot be unmarshalled
     */
    public DOMXMLSignature(Element sigElem, XMLCryptoContext context) 
	throws MarshalException {
        localSigElem = sigElem;
        ownerDoc = localSigElem.getOwnerDocument();

        // get Id attribute, if specified
	id = DOMUtils.getAttributeValue(localSigElem, "Id");

	// unmarshal SignedInfo
	Element siElem = DOMUtils.getFirstChildElement(localSigElem);
	si = new DOMSignedInfo(siElem, context);

	// unmarshal SignatureValue 
	Element sigValElem = DOMUtils.getNextSiblingElement(siElem);
	sv = new DOMSignatureValue(sigValElem);

	// unmarshal KeyInfo, if specified
	Element nextSibling = DOMUtils.getNextSiblingElement(sigValElem);
	if (nextSibling != null && nextSibling.getLocalName().equals("KeyInfo")) {
	    ki = new DOMKeyInfo(nextSibling, context);
	    nextSibling = DOMUtils.getNextSiblingElement(nextSibling);
	}

	// unmarshal Objects, if specified
	if (nextSibling == null) {
	    objects = Collections.EMPTY_LIST;
	} else {
	    List tempObjects = new ArrayList();
	    while (nextSibling != null) {
	        tempObjects.add(new DOMXMLObject(nextSibling, context));
	        nextSibling = DOMUtils.getNextSiblingElement(nextSibling);
	    }
	    objects = Collections.unmodifiableList(tempObjects);	
	}
    }

    public String getId() {
        return id;
    }

    public KeyInfo getKeyInfo() {
        return ki;
    }

    public SignedInfo getSignedInfo() {
        return si;
    }

    public List getObjects() {
        return objects;
    }

    public SignatureValue getSignatureValue() {
	return sv;
    }

    public KeySelectorResult getKeySelectorResult() {
	return ksr;
    }

    public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
	throws MarshalException {
	marshal(parent, null, dsPrefix, context);
    }

    public void marshal(Node parent, Node nextSibling, String dsPrefix,
        DOMCryptoContext context) throws MarshalException {
        ownerDoc = DOMUtils.getOwnerDocument(parent);

        sigElem = DOMUtils.createElement
            (ownerDoc, "Signature", XMLSignature.XMLNS, dsPrefix);

        // append xmlns attribute
        //XXX I think this is supposed to be automatically inserted when
        //XXX serializing a DOM2 tree, but doesn't seem to work with JAXP/Xalan
        if (dsPrefix == null) {
            sigElem.setAttributeNS
		("http://www.w3.org/2000/xmlns/", "xmlns", XMLSignature.XMLNS);
        } else {
            sigElem.setAttributeNS
		("http://www.w3.org/2000/xmlns/", "xmlns:" + dsPrefix, 
		 XMLSignature.XMLNS);
        }

	// create and append SignedInfo element
	((DOMSignedInfo) si).marshal(sigElem, dsPrefix, context);

        // create and append SignatureValue element
	((DOMSignatureValue) sv).marshal(sigElem, dsPrefix, context);

	// create and append KeyInfo element if necessary
	if (ki != null) {
	    ((DOMKeyInfo) ki).marshal(sigElem, null, dsPrefix, context);
	}

	// create and append Object elements if necessary
	for (int i = 0, size = objects.size(); i < size; i++) {
	    ((DOMXMLObject) objects.get(i)).marshal(sigElem, dsPrefix, context);
	}

	// append Id attribute
        DOMUtils.setAttributeID(sigElem, "Id", id);
	    
	parent.insertBefore(sigElem, nextSibling);
    }

    public boolean validate(XMLValidateContext vc) 
	throws XMLSignatureException {

	if (vc == null) {
	    throw new NullPointerException("validateContext is null");
	}

	if (validated) {
	    return validationStatus;
	}

        // validate all References
        List refs = this.si.getReferences();
        boolean validateRefs = true;
	for (int i = 0, size = refs.size(); validateRefs && i < size; i++) {
            Reference ref = (Reference) refs.get(i);
            boolean refValid = ref.validate(vc);
	    if (log.isLoggable(Level.FINE)) {
                log.log(Level.FINE, "Reference[" + ref.getURI() + "] is valid: "
		    + refValid);
	    }
            validateRefs &= refValid;
        }
        if (!validateRefs) {
	    if (log.isLoggable(Level.FINE)) {
                log.log(Level.FINE, "Couldn't validate the References");
	    }
	    validationStatus = false;
	    validated = true;
	    return validationStatus;
        }

	// validate the signature
	boolean sigValidity = sv.validate(vc);
	if (!sigValidity) {
	    validationStatus = false;
	    validated = true;
	    return validationStatus;
        }

	// validate Manifests, if property set
        boolean validateMans = true;
	if (Boolean.TRUE.equals(vc.getProperty
	    ("org.jcp.xml.dsig.validateManifests"))) {

	    for (int i=0, size=objects.size(); validateMans && i < size; i++) {
                XMLObject xo = (XMLObject) objects.get(i);
                List content = xo.getContent();
		int csize = content.size();
	        for (int j = 0; validateMans && j < csize; j++) {
                    XMLStructure xs = (XMLStructure) content.get(j);
                    if (xs instanceof Manifest) {
	    		if (log.isLoggable(Level.FINE)) {
                            log.log(Level.FINE, "validating manifest");
			}
                        Manifest man = (Manifest) xs;
                        List manRefs = man.getReferences();
			int rsize = manRefs.size();
	        	for (int k = 0; validateMans && k < rsize; k++) {
                            Reference ref = (Reference) manRefs.get(k);
                            boolean refValid = ref.validate(vc);
    		            if (log.isLoggable(Level.FINE)) {
                               log.log(Level.FINE, "Manifest ref[" 
				    + ref.getURI() + "] is valid: " + refValid);
			    }
			    validateMans &= refValid;
			}
                    }
                }
            }
	}

	validationStatus = validateMans;
	validated = true;
	return validationStatus;
    }

    public void sign(XMLSignContext signContext) 
	throws MarshalException, XMLSignatureException {
	if (signContext == null) {
	    throw new NullPointerException("signContext cannot be null");
	}
        DOMSignContext context = (DOMSignContext) signContext;
        if (context != null) {
            marshal(context.getParent(), context.getNextSibling(),
                DOMUtils.getSignaturePrefix(context), context);
        }

	// generate references and signature value
	List allReferences = new ArrayList(si.getReferences());

	// traverse the Signature and register all objects with IDs that
	// may contain References
	signatureIdMap = new HashMap();
	signatureIdMap.put(id, this);
	signatureIdMap.put(si.getId(), si);
	List refs = si.getReferences();
	for (int i = 0, size = refs.size(); i < size; i++) {
            Reference ref = (Reference) refs.get(i);
            signatureIdMap.put(ref.getId(), ref);
	}
	for (int i = 0, size = objects.size(); i < size; i++) {
            XMLObject obj = (XMLObject) objects.get(i);
            signatureIdMap.put(obj.getId(), obj);
            List content = obj.getContent();
	    for (int j = 0, csize = content.size(); j < csize; j++) {
		XMLStructure xs = (XMLStructure) content.get(j);
		if (xs instanceof Manifest) {
                    Manifest man = (Manifest) xs;
                    signatureIdMap.put(man.getId(), man);
                    List manRefs = man.getReferences();
	    	    for (int k = 0, msize = manRefs.size(); k < msize; k++) {
			Reference ref = (Reference) manRefs.get(k);
			allReferences.add(ref);
			signatureIdMap.put(ref.getId(), ref);
                    }
		}
            }
	}

        // generate/digest each reference
	for (int i = 0, size = allReferences.size(); i < size; i++) {
            DOMReference ref = (DOMReference) allReferences.get(i);
            digestReference(ref, signContext);
	}

        // do final sweep to digest any references that were skipped or missed
	for (int i = 0, size = allReferences.size(); i < size; i++) {
            DOMReference ref = (DOMReference) allReferences.get(i);
            if (ref.isDigested()) {
		continue;
            }
            ref.digest(signContext);
	}

        Key signingKey = null;
	KeySelectorResult ksr = null;
	try {
            ksr = signContext.getKeySelector().select
		(ki, KeySelector.Purpose.SIGN,
		si.getSignatureMethod(), signContext);
            signingKey = ksr.getKey();
            if (signingKey == null) {
		throw new XMLSignatureException("the keySelector did not " +
            	"find a signing key");
            }
	} catch (KeySelectorException kse) {
            throw new XMLSignatureException("cannot find signing key", kse);
	}

	// calculate signature value
	byte[] val = null;
	try {
            val = ((DOMSignatureMethod) si.getSignatureMethod()).sign
		(signingKey, (DOMSignedInfo) si, signContext);
	} catch (InvalidKeyException ike) {
            throw new XMLSignatureException(ike);
	}

	if (log.isLoggable(Level.FINE)) {
            log.log(Level.FINE, "SignatureValue = " + val);        
	}
	((DOMSignatureValue) sv).setValue(val);

        this.localSigElem = sigElem;   
	this.ksr = ksr;
    }

    public boolean equals(Object o) {
	if (this == o) {
	    return true;
	}

	if (!(o instanceof XMLSignature)) {
	    return false;
	}
	XMLSignature osig = (XMLSignature) o;

	boolean idEqual = 
	    (id == null ? osig.getId() == null : id.equals(osig.getId()));
	boolean keyInfoEqual = 
	    (ki == null ? osig.getKeyInfo() == null : 
	     ki.equals(osig.getKeyInfo()));

	return (idEqual && keyInfoEqual && 
	    sv.equals(osig.getSignatureValue()) &&
	    si.equals(osig.getSignedInfo()) && 
	    objects.equals(osig.getObjects()));
    }

    private void digestReference(DOMReference ref, XMLSignContext signContext)
	throws XMLSignatureException {
	if (ref.isDigested()) {
       	    return;
	}
        // check dependencies
	String uri = ref.getURI();
	if (Utils.sameDocumentURI(uri)) {
            String id = Utils.parseIdFromSameDocumentURI(uri);
            if (id != null && signatureIdMap.containsKey(id)) {
		Object obj = signatureIdMap.get(id);
		if (obj instanceof DOMReference) {
                    digestReference((DOMReference) obj, signContext);
		} else if (obj instanceof Manifest) {
                    Manifest man = (Manifest) obj;
                    List manRefs = man.getReferences();
		    for (int i = 0, size = manRefs.size(); i < size; i++) {
			digestReference
                 	    ((DOMReference) manRefs.get(i), signContext);
		    }
		}
            }
	    // if uri="" and there are XPath Transforms, there may be
	    // reference dependencies in the XPath Transform - so be on
	    // the safe side, and skip and do at end in the final sweep
	    if (uri.length() == 0) {
		List transforms = ref.getTransforms();
	        for (int i = 0, size = transforms.size(); i < size; i++) {
		    Transform transform = (Transform) transforms.get(i);
		    String transformAlg = transform.getAlgorithm();
		    if (transformAlg.equals(Transform.XPATH) ||
			transformAlg.equals(Transform.XPATH2)) {
                	return;
                    }
            	}
            }
	}
	ref.digest(signContext);
    }

    public class DOMSignatureValue extends DOMStructure 
	implements SignatureValue {

	private String id;
        private byte[] value;
        private String valueBase64;
        private Element sigValueElem;
	private boolean validated = false;
	private boolean validationStatus;

	DOMSignatureValue(String id) {
	    this.id = id;
	}

	DOMSignatureValue(Element sigValueElem) throws MarshalException {
	    try {
	        // base64 decode signatureValue
	        value = Base64.decode(sigValueElem);
	    } catch (Base64DecodingException bde) {
	        throw new MarshalException(bde);
	    }

	    id = DOMUtils.getAttributeValue(sigValueElem, "Id");
	    this.sigValueElem = sigValueElem;
	}

	public String getId() {
	    return id;
	}

        public byte[] getValue() {
	    return (value == null) ? null : (byte[]) value.clone();
        }

        public boolean validate(XMLValidateContext validateContext) 
	    throws XMLSignatureException {

	    if (validateContext == null) {
		throw new NullPointerException("context cannot be null");
	    }

	    if (validated) {
		return validationStatus;
	    }

	    // get validating key
	    SignatureMethod sm = si.getSignatureMethod();
	    Key validationKey = null;
	    KeySelectorResult ksResult;
	    try {
		ksResult = validateContext.getKeySelector().select
		    (ki, KeySelector.Purpose.VERIFY, sm, validateContext);
		validationKey = ksResult.getKey();
		if (validationKey == null) {
		    throw new XMLSignatureException("the keyselector did " +
			"not find a validation key");
		}
	    } catch (KeySelectorException kse) {
		throw new XMLSignatureException("cannot find validation " +
		    "key", kse);
	    }

	    // canonicalize SignedInfo and verify signature
	    try {
		validationStatus = ((DOMSignatureMethod) sm).verify
		    (validationKey, (DOMSignedInfo) si, value, validateContext);
	    } catch (Exception e) {
		throw new XMLSignatureException(e);
	    }

	    validated = true;
	    ksr = ksResult;
	    return validationStatus;
        }

        public boolean equals(Object o) {
	    if (this == o) {
	        return true;
	    }

	    if (!(o instanceof SignatureValue)) {
	        return false;
	    }
	    SignatureValue osv = (SignatureValue) o;

	    boolean idEqual = 
	        (id == null ? osv.getId() == null : id.equals(osv.getId()));

	    //XXX compare signature values?
	    return idEqual;
	}

	public void marshal(Node parent, String dsPrefix,
	    DOMCryptoContext context) throws MarshalException {

            // create SignatureValue element
            sigValueElem = DOMUtils.createElement
                (ownerDoc, "SignatureValue", XMLSignature.XMLNS, dsPrefix);
	    if (valueBase64 != null) {
	        sigValueElem.appendChild(ownerDoc.createTextNode(valueBase64));
	    }

            // append Id attribute, if specified
            DOMUtils.setAttributeID(sigValueElem, "Id", id);
            parent.appendChild(sigValueElem);
	}

	void setValue(byte[] value) {
	    this.value = value;
            valueBase64 = Base64.encode(value);
            sigValueElem.appendChild(ownerDoc.createTextNode(valueBase64));
	}
    }
}

Generated By: JavaOnTracks Doclet 0.1.4     ©Thibaut Colar