/*
 * Copyright 2006-2009 The Apache Software Foundation.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
/*
 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
 */
package javax.xml.crypto.test.dsig;

import java.io.*;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.security.utils.Constants;

import junit.framework.*;

import javax.xml.crypto.test.KeySelectors;

/**
 * Test that recreates merlin-xmldsig-twenty-three test vectors but with
 * different keys and X.509 data.
 *
 * @author Sean Mullan
 */
public class CreateBaltimore23Test extends TestCase {

    private XMLSignatureFactory fac;
    private KeyInfoFactory kifac;
    private DocumentBuilder db;
    private CanonicalizationMethod withoutComments;
    private Transform withComments;
    private SignatureMethod dsaSha1, rsaSha1;
    private DigestMethod sha1;
    private KeyInfo dsa, rsa;
    private KeySelector kvks = new KeySelectors.KeyValueKeySelector();
    private KeySelector sks; 
    private Key signingKey;
    private PublicKey validatingKey;
    private Certificate signingCert;
    private KeyStore ks;

    static {
        Security.insertProviderAt
            (new org.jcp.xml.dsig.internal.dom.XMLDSigRI(), 1);
    }

    public CreateBaltimore23Test(String name) {
	super(name);
    }

    public void setUp() throws Exception {
	fac = XMLSignatureFactory.getInstance
	    ("DOM", new org.jcp.xml.dsig.internal.dom.XMLDSigRI());
	kifac = fac.getKeyInfoFactory();
	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	dbf.setNamespaceAware(true);
	db = dbf.newDocumentBuilder();

	// get key & self-signed certificate from keystore
	String fs = System.getProperty("file.separator");
	String base = System.getProperty("basedir") == null ? "./": System.getProperty("basedir");

	FileInputStream fis = new FileInputStream
	    (base + fs + "data" + fs + "test.jks");
	ks = KeyStore.getInstance("JKS");
	ks.load(fis, "changeit".toCharArray());
	signingKey = ks.getKey("mullan", "changeit".toCharArray());
	signingCert = ks.getCertificate("mullan");
	validatingKey = signingCert.getPublicKey();

	// create common objects
	withoutComments = fac.newCanonicalizationMethod
	    (CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null);
	withComments = fac.newTransform
	    (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, 
	     (TransformParameterSpec) null);
	dsaSha1 = fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null);
	sha1 = fac.newDigestMethod(DigestMethod.SHA1, null);
	dsa = kifac.newKeyInfo(Collections.singletonList
	    (kifac.newKeyValue(validatingKey)));
	rsa = kifac.newKeyInfo(Collections.singletonList
	    (kifac.newKeyValue(TestUtils.getPublicKey("RSA"))));
	rsaSha1 = fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
        sks = new KeySelectors.SecretKeySelector("secret".getBytes("ASCII"));

    }

    public void test_create_signature_enveloped_dsa() throws Exception {
	// create SignedInfo
	SignedInfo si = fac.newSignedInfo
	    (withoutComments, dsaSha1, Collections.singletonList
		(fac.newReference
		    ("", sha1, Collections.singletonList
	                (fac.newTransform(Transform.ENVELOPED, 
			 (TransformParameterSpec) null)), 
	         null, null)));

	// create XMLSignature
	XMLSignature sig = fac.newXMLSignature(si, dsa);

	Document doc = db.newDocument();
	Element envelope = doc.createElementNS
	    ("http://example.org/envelope", "Envelope");
	envelope.setAttributeNS
	    (Constants.NamespaceSpecNS, "xmlns", "http://example.org/envelope");
	doc.appendChild(envelope);

	DOMSignContext dsc = new DOMSignContext(signingKey, envelope);

	sig.sign(dsc);

	DOMValidateContext dvc = new DOMValidateContext
	    (kvks, envelope.getFirstChild());
	XMLSignature sig2 = fac.unmarshalXMLSignature(dvc);

	assertTrue(sig.equals(sig2));

	assertTrue(sig2.validate(dvc));
    }

    public void test_create_signature_enveloping_b64_dsa() throws Exception {
	test_create_signature_enveloping(dsaSha1, dsa, signingKey, kvks, true);
    }

    public void test_create_signature_enveloping_dsa() throws Exception {
	test_create_signature_enveloping(dsaSha1, dsa, signingKey, kvks, false);
    }

    public void test_create_signature_enveloping_hmac_sha1_40() 
	throws Exception {
	SignatureMethod hmacSha1 = fac.newSignatureMethod
	    (SignatureMethod.HMAC_SHA1, new HMACParameterSpec(40));
        try {
            test_create_signature_enveloping(hmacSha1, null,
	        TestUtils.getSecretKey("secret".getBytes("ASCII")), sks, false);
            fail("Expected HMACOutputLength Exception");
        } catch (XMLSignatureException xse) {
            System.out.println(xse.getMessage());
            // pass
        }
    }

    public void test_create_signature_enveloping_hmac_sha1()
	throws Exception {
	SignatureMethod hmacSha1 = fac.newSignatureMethod
	    (SignatureMethod.HMAC_SHA1, null);
        test_create_signature_enveloping(hmacSha1, null,
	    TestUtils.getSecretKey("secret".getBytes("ASCII")), sks, false);
    }

    public void test_create_signature_enveloping_rsa() throws Exception {
	test_create_signature_enveloping(rsaSha1, rsa, 
	    TestUtils.getPrivateKey("RSA"), kvks, false);
    }

    public void test_create_signature_external_b64_dsa() throws Exception {
	test_create_signature_external(dsaSha1, dsa, signingKey, kvks, true);
    }

    public void test_create_signature_external_dsa() throws Exception {
	test_create_signature_external(dsaSha1, dsa, signingKey, kvks, false);
    }

    public void test_create_signature_keyname() throws Exception {
	KeyInfo kn = kifac.newKeyInfo(Collections.singletonList
	    (kifac.newKeyName("mullan")));
	test_create_signature_external(dsaSha1, kn, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature_retrievalmethod_rawx509crt() 
	throws Exception {
	KeyInfo rm = kifac.newKeyInfo(Collections.singletonList
	    (kifac.newRetrievalMethod
	    ("certs/mullan.crt", X509Data.RAW_X509_CERTIFICATE_TYPE, null)));
	test_create_signature_external(dsaSha1, rm, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature_x509_crt_crl() throws Exception {
	List xds = new ArrayList();
	CertificateFactory cf = CertificateFactory.getInstance("X.509");
	xds.add(signingCert);
	String fs = System.getProperty("file.separator");
	FileInputStream fis = new FileInputStream
	    (System.getProperty("basedir") + fs + "data" + fs + "ie" + fs +
	     "baltimore" + fs + "merlin-examples" + fs + 
	     "merlin-xmldsig-twenty-three" + fs + "certs" + fs + "crl");
	X509CRL crl = (X509CRL) cf.generateCRL(fis);
	fis.close();
	xds.add(crl);
	KeyInfo crt_crl = kifac.newKeyInfo(Collections.singletonList
            (kifac.newX509Data(xds)));

	test_create_signature_external(dsaSha1, crt_crl, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature_x509_crt() throws Exception {
	KeyInfo crt = kifac.newKeyInfo(Collections.singletonList
            (kifac.newX509Data(Collections.singletonList(signingCert))));

	test_create_signature_external(dsaSha1, crt, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature_x509_is() throws Exception {
	KeyInfo is = kifac.newKeyInfo(Collections.singletonList
	    (kifac.newX509Data(Collections.singletonList
	    (kifac.newX509IssuerSerial
	    ("CN=Sean Mullan,DC=sun,DC=com",
	    new BigInteger("47cdb772", 16))))));
	test_create_signature_external(dsaSha1, is, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature_x509_ski() throws Exception {
	KeyInfo ski = kifac.newKeyInfo(Collections.singletonList
            (kifac.newX509Data(Collections.singletonList
	    ("keyid".getBytes("ASCII")))));

	test_create_signature_external(dsaSha1, ski, signingKey,
	    KeySelector.singletonKeySelector(validatingKey), false);
    }

    public void test_create_signature_x509_sn() throws Exception {
	KeyInfo sn = kifac.newKeyInfo(Collections.singletonList
            (kifac.newX509Data(Collections.singletonList
	    ("CN=Sean Mullan,DC=sun,DC=com"))));

	test_create_signature_external(dsaSha1, sn, signingKey,
	    new X509KeySelector(ks), false);
    }

    public void test_create_signature() throws Exception {
	// set up reusable objects
	Transform env = fac.newTransform(Transform.ENVELOPED, 
	    (TransformParameterSpec) null);

	// create references
	List refs = new ArrayList();
	
	// Reference 1
	refs.add(fac.newReference("http://www.w3.org/TR/xml-stylesheet", sha1));

	// Reference 2
        refs.add(fac.newReference
	    ("http://www.w3.org/Signature/2002/04/xml-stylesheet.b64", 
	    sha1, Collections.singletonList
            (fac.newTransform(Transform.BASE64, 
	     (TransformParameterSpec) null)), null, null));

	// Reference 3
        refs.add(fac.newReference("#object-1", sha1, Collections.singletonList
	    (fac.newTransform(Transform.XPATH, 
	    new XPathFilterParameterSpec("self::text()"))), 
	    XMLObject.TYPE, null));

	// Reference 4
	String expr = "\n"
          + " ancestor-or-self::dsig:SignedInfo			 " + "\n"
          + "  and                                               " + "\n"
          + " count(ancestor-or-self::dsig:Reference |		 " + "\n"
          + "	   here()/ancestor::dsig:Reference[1]) >	 " + "\n"
          + " count(ancestor-or-self::dsig:Reference)		 " + "\n"
          + "  or                                                " + "\n"
          + " count(ancestor-or-self::node() |			 " + "\n"
          + "	   id('notaries')) =				 " + "\n"
          + " count(ancestor-or-self::node())			 " + "\n";

	new XPathFilterParameterSpec(expr,
	    Collections.singletonMap("dsig", XMLSignature.XMLNS));
//        refs.add(fac.newReference("", sha1, Collections.singletonList
//	    (fac.newTransform(Transform.XPATH, xfp)),
//	    XMLObject.TYPE, null));

	// Reference 5
        refs.add(fac.newReference("#object-2", sha1, Collections.singletonList
	    (fac.newTransform(Transform.BASE64, (TransformParameterSpec) null)),
	    XMLObject.TYPE, null));

	// Reference 6
        refs.add(fac.newReference
	    ("#manifest-1", sha1, null, Manifest.TYPE, null));

	// Reference 7
        refs.add(fac.newReference("#signature-properties-1", sha1, null, 
	    SignatureProperties.TYPE, null));

	// Reference 8
	List transforms = new ArrayList();
	transforms.add(env);
        refs.add(fac.newReference("", sha1, transforms, null, null));

	// Reference 9
	transforms.add(withComments);
        refs.add(fac.newReference("", sha1, transforms, null, null));

	// Reference 10
        refs.add(fac.newReference("#xpointer(/)",
	    sha1, Collections.singletonList(env), null, null));

	// Reference 11
        refs.add(fac.newReference("#xpointer(/)", sha1, transforms, 
	    null, null));

	// Reference 12
        refs.add
	    (fac.newReference("#object-3", sha1, null, XMLObject.TYPE, null));

	// Reference 13
        refs.add(fac.newReference("#object-3", sha1, 
	    Collections.singletonList(withComments), XMLObject.TYPE, null));

	// Reference 14
        refs.add(fac.newReference("#xpointer(id('object-3'))", sha1, null, 
	    XMLObject.TYPE, null));

	// Reference 15
        refs.add(fac.newReference("#xpointer(id('object-3'))", sha1, 
	    Collections.singletonList(withComments), XMLObject.TYPE, null));

	// Reference 16
        refs.add(fac.newReference("#reference-2", sha1));

	// Reference 17
        refs.add(fac.newReference("#manifest-reference-1", sha1, null,
	    null, "reference-1"));

	// Reference 18
        refs.add(fac.newReference("#reference-1", sha1, null, null,
	    "reference-2"));

	// create SignedInfo
	SignedInfo si = fac.newSignedInfo(withoutComments, dsaSha1, refs);

	// create keyinfo
	XPathFilterParameterSpec xpf = new XPathFilterParameterSpec(
	    "ancestor-or-self::dsig:X509Data",
	    Collections.singletonMap("dsig", XMLSignature.XMLNS));
	RetrievalMethod rm = kifac.newRetrievalMethod("#object-4", 
	    X509Data.TYPE, Collections.singletonList(fac.newTransform
	    (Transform.XPATH, xpf)));
	KeyInfo ki = kifac.newKeyInfo(Collections.singletonList(rm), null);

	Document doc = db.newDocument();

	// create objects
	List objs = new ArrayList();

	// Object 1
	objs.add(fac.newXMLObject(Collections.singletonList
	    (new DOMStructure(doc.createTextNode("I am the text."))), 
	    "object-1", "text/plain", null));

	// Object 2
	objs.add(fac.newXMLObject(Collections.singletonList
	    (new DOMStructure(doc.createTextNode("SSBhbSB0aGUgdGV4dC4="))), 
	    "object-2", "text/plain", Transform.BASE64));

	// Object 3
	Element nc = doc.createElementNS(null, "NonCommentandus");
	nc.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "");
        nc.appendChild(doc.createComment(" Commentandum "));
	objs.add(fac.newXMLObject(Collections.singletonList
	    (new DOMStructure(nc)), "object-3", null, null));

	// Manifest
	List manRefs = new ArrayList();

	// Manifest Reference 1
	manRefs.add(fac.newReference("http://www.w3.org/TR/xml-stylesheet",
	    sha1, null, null, "manifest-reference-1"));

	// Manifest Reference 2
	manRefs.add(fac.newReference("#reference-1", sha1));

	// Manifest Reference 3
	List manTrans = new ArrayList();
        String xslt = ""
	  + "<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'\n"
	  + "		 xmlns='http://www.w3.org/TR/xhtml1/strict' \n"
	  + "		 exclude-result-prefixes='foo' \n"
	  + "		 version='1.0'>\n"
	  + "  <xsl:output encoding='UTF-8' \n"
	  + "		indent='no' \n"
	  + "		method='xml' />\n"
	  + "  <xsl:template match='/'>\n"
	  + "    <html>\n"
	  + "	<head>\n"
	  + "	 <title>Notaries</title>\n"
	  + "	</head>\n"
	  + "	<body>\n"
	  + "	 <table>\n"
	  + "	   <xsl:for-each select='Notaries/Notary'>\n"
	  + "		<tr>\n"
	  + "		<th>\n"
	  + "		 <xsl:value-of select='@name' />\n"
	  + "		</th>\n"
	  + "		</tr>\n"
	  + "	   </xsl:for-each>\n"
	  + "	 </table>\n"
	  + "	</body>\n"
	  + "    </html>\n"
	  + "  </xsl:template>\n"
	  + "</xsl:stylesheet>\n";
	Document docxslt = db.parse(new ByteArrayInputStream(xslt.getBytes()));
        Node xslElem = docxslt.getDocumentElement();

	manTrans.add(fac.newTransform(Transform.XSLT, 
	    new XSLTTransformParameterSpec(new DOMStructure(xslElem))));
	manTrans.add(fac.newTransform(CanonicalizationMethod.INCLUSIVE, 
	    (TransformParameterSpec) null));
// Comment out Manifest Reference 3, for some reason xalan is throwing NPE
// when Transform is processed.
//	manRefs.add(fac.newReference("#notaries", sha1, manTrans, null, null));

	objs.add(fac.newXMLObject(Collections.singletonList
	    (fac.newManifest(manRefs, "manifest-1")), null, null, null));

	// SignatureProperties
	Element sa = doc.createElementNS("urn:demo", "SignerAddress");
	sa.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "urn:demo");
	Element ip = doc.createElementNS("urn:demo", "IP");
	ip.appendChild(doc.createTextNode("192.168.21.138"));
	sa.appendChild(ip);
	SignatureProperty sp = fac.newSignatureProperty
	    (Collections.singletonList(new DOMStructure(sa)), 
	    "#signature", null);
	SignatureProperties sps = fac.newSignatureProperties
	    (Collections.singletonList(sp), "signature-properties-1");
	objs.add(fac.newXMLObject(Collections.singletonList(sps), null, 
	    null, null));

	// Object 4
	List xds = new ArrayList();
	xds.add("CN=Sean Mullan,DC=sun,DC=com");
	xds.add(kifac.newX509IssuerSerial
	    ("CN=Sean Mullan,DC=sun,DC=com",
	    new BigInteger("47cdb772", 16)));
	xds.add(signingCert);
	objs.add(fac.newXMLObject(Collections.singletonList
	    (kifac.newX509Data(xds)), "object-4", null, null));

	// create XMLSignature
	XMLSignature sig = fac.newXMLSignature(si, ki, objs, "signature", null);

	// create envelope header
	Element envelope = doc.createElementNS
	    ("http://example.org/usps", "Envelope");
	envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", 
	    "http://example.org/usps");
        envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:foo", 
	    "http://example.org/foo");
	doc.appendChild(envelope);
	Element dearSir = doc.createElementNS 
	    ("http://example.org/usps", "DearSir");
	dearSir.appendChild(doc.createTextNode("foo"));
	envelope.appendChild(dearSir);
	Element body = doc.createElementNS("http://example.org/usps", "Body");
	body.appendChild(doc.createTextNode("bar"));
	envelope.appendChild(body);
	Element ys = doc.createElementNS 
	    ("http://example.org/usps", "YoursSincerely");
	envelope.appendChild(ys);

	// create envelope footer
	Element ps = doc.createElementNS
	    ("http://example.org/usps", "PostScript");
	ps.appendChild(doc.createTextNode("bar"));
	envelope.appendChild(ps);
	Element notaries = doc.createElementNS(null, "Notaries");
	notaries.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "");
	notaries.setAttributeNS(null, "Id", "notaries");
	Element notary1 = doc.createElementNS(null, "Notary");
	notary1.setAttributeNS(null, "name", "Great, A. T.");
	Element notary2 = doc.createElementNS(null, "Notary");
	notary2.setAttributeNS(null, "name", "Hun, A. T.");
	notaries.appendChild(notary1);
	notaries.appendChild(notary2);
	envelope.appendChild(notaries);
	envelope.appendChild(doc.createComment(" Commentary "));

	DOMSignContext dsc = new DOMSignContext(signingKey, ys);
	dsc.setIdAttributeNS(notaries, null, "Id");

	sig.sign(dsc);

	// DOM L2 does not support the creation of DOCTYPEs, so instead
        // we insert it before the document using a StringWriter
//	String docType = 
//	    "<!DOCTYPE Envelope [\n"
//  	  + "<!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>\n"
//          + "<!ENTITY c14n 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'>\n"
//          + "<!ENTITY xpath 'http://www.w3.org/TR/1999/REC-xpath-19991116'>\n"
//          + "<!ENTITY xslt 'http://www.w3.org/TR/1999/REC-xslt-19991116'>\n"
//          + "<!ATTLIST Notaries Id ID #IMPLIED>\n"
//          + "]>\n";
	StringWriter sw = new StringWriter();
//	sw.write(docType);

        dumpDocument(doc, sw);

	// read document back into DOM tree
	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	dbf.setNamespaceAware(true);
	dbf.setValidating(false);
	try {
	    doc = dbf.newDocumentBuilder().parse
	        (new InputSource(new StringReader(sw.toString())));
	} catch (SAXParseException spe) {
	    System.err.println("line:" + spe.getLineNumber());
	    System.err.println("xml:" + sw.toString());
	}
	Element sigElement = SignatureValidator.getSignatureElement(doc);
	if (sigElement == null) {
            throw new Exception("Couldn't find signature Element");
	}

	DOMValidateContext dvc = new DOMValidateContext
	    (new X509KeySelector(ks), sigElement);
	File f = new File(
	    System.getProperty("dir.test.vector.baltimore") + 
            System.getProperty("file.separator") +
	    "merlin-xmldsig-twenty-three" +
            System.getProperty("file.separator"));
	dvc.setBaseURI(f.toURI().toString());

	// register Notaries ID
//	Element notariesElem = 
//	    (Element) doc.getElementsByTagName("Notaries").item(0);
//	dvc.setIdAttributeNS(notariesElem, "", "Id");
//	notariesElem.setIdAttributeNS("", "Id", true);
	    
	XMLSignature sig2 = fac.unmarshalXMLSignature(dvc);

	assertTrue(sig.equals(sig2));
	assertTrue(sig2.validate(dvc));
    }

    private void dumpDocument(Document doc, Writer w) throws Exception {
	TransformerFactory tf = TransformerFactory.newInstance();
	Transformer trans = tf.newTransformer();
//	trans.setOutputProperty(OutputKeys.INDENT, "yes");
	trans.transform(new DOMSource(doc), new StreamResult(w));
    }

    private void test_create_signature_external
	(SignatureMethod sm, KeyInfo ki, Key signingKey, KeySelector ks,
	boolean b64) throws Exception {

	// create reference
	Reference ref;
	if (b64) {
	    ref = fac.newReference
		("http://www.w3.org/Signature/2002/04/xml-stylesheet.b64", 
		sha1, Collections.singletonList
        	(fac.newTransform(Transform.BASE64, 
		 (TransformParameterSpec) null)), null, null);
	} else {
	    ref = fac.newReference
		("http://www.w3.org/Signature/2002/04/xml-stylesheet.b64",sha1);
	}

	// create SignedInfo
	SignedInfo si = fac.newSignedInfo(withoutComments, sm, 
	    Collections.singletonList(ref));

	Document doc = db.newDocument();

	// create XMLSignature
	XMLSignature sig = fac.newXMLSignature(si, ki);

	DOMSignContext dsc = new DOMSignContext(signingKey, doc);

	sig.sign(dsc);

/**
	System.out.println("doc is:");
	StringWriter sw = new StringWriter();
        dumpDocument(doc, sw);
	System.out.println(sw.toString());
**/

	DOMValidateContext dvc = new DOMValidateContext
	    (ks, doc.getDocumentElement());
	String fs = System.getProperty("file.separator");
	File f = new File(
	    System.getProperty("basedir") + fs + "data" + fs + "ie" + fs +
	    "baltimore" + fs + "merlin-examples" + fs +
	    "merlin-xmldsig-twenty-three" + fs);
	dvc.setBaseURI(f.toURI().toString()); 
	    
	XMLSignature sig2 = fac.unmarshalXMLSignature(dvc);

	assertTrue(sig.equals(sig2));
	assertTrue(sig2.validate(dvc));
    }

    private void test_create_signature_enveloping
	(SignatureMethod sm, KeyInfo ki, Key signingKey, KeySelector ks, 
	boolean b64) throws Exception {

	// create reference
	Reference ref;
	if (b64) {
	    ref = fac.newReference("#object", sha1, Collections.singletonList
        	(fac.newTransform(Transform.BASE64, 
		 (TransformParameterSpec) null)), null, null);
	} else {
	    ref = fac.newReference("#object", sha1);
	}

	// create SignedInfo
	SignedInfo si = fac.newSignedInfo(withoutComments, sm, 
	    Collections.singletonList(ref));

	Document doc = db.newDocument();
	// create Objects
	XMLObject obj = fac.newXMLObject(Collections.singletonList
	    (new DOMStructure(doc.createTextNode("some text"))), 
	    "object", null, null);

	// create XMLSignature
	XMLSignature sig = fac.newXMLSignature
	    (si, ki, Collections.singletonList(obj), null, null);

	DOMSignContext dsc = new DOMSignContext(signingKey, doc);

	sig.sign(dsc);

	DOMValidateContext dvc = new DOMValidateContext
	    (ks, doc.getDocumentElement());
	XMLSignature sig2 = fac.unmarshalXMLSignature(dvc);

	assertTrue(sig.equals(sig2));
	assertTrue(sig2.validate(dvc));
    }

    public static void main(String[] args) throws Exception {
	CreateBaltimore23Test test = new CreateBaltimore23Test("main");
	test.setUp();
//	test.test_create_signature();
    }
}
