This morning I did another test: I made signatures using XPath2Container, and now I have good signature and verifications.
I replaced the section

// Set XPATH and adding as a transform
XPathContainer xpathContainer = new XPathContainer(doc);
xpathContainer.setXPathNamespaceContext("ds",
            Constants.SignatureSpecNS);

// Setting elements 'lastname' to be signed
String xpath = "/users/user/lastname";
xpathContainer.setXPath(xpath);
transforms.addTransform(Transforms.TRANSFORM_XPATH,
            xpathContainer.getElementPlusReturns());


with the new section

// With XPATH Filter 2
String[][] filters = new String[][] {
                {XPath2FilterContainer.INTERSECT, "//firstname" } };
transforms.addTransform(Transforms.TRANSFORM_XPATH2FILTER,
                        XPath2FilterContainer.newInstances(doc,
                                                        filters));

With this replacement now I have good signatures



Daniele Gagliardi ha scritto:
I have a strange verification behaviour.
I'm trying to sign portions of a XML document using ds:XPath element,
as follows (the XML documents contains some users info: firstname, lastname, age and serial, each of one is represented by a XML element):

//... opening keystore
File keystoreFile= new File(...);
String privateKeyPass = ...;
String privateKeyAlias = ...;
String keystoreType = "pkcs12";
KeyStore ks = KeyStore.getInstance(keystoreType);
FileInputStream fis = new FileInputStream(keystoreFile);
ks.load(fis, keystorePass.toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias,
                  privateKeyPass.toCharArray());


// ...loading xml document
File xmlDocument = new File("generic-users.xml");

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlDocument);

// ... signing it:
// Init signature file and base URI
File signatureFile = new File("enveloped-signature.xml");
String baseURI = signatureFile.toURL().toString();

// Generate signature element and append it to root
XMLSignature sig = new XMLSignature(doc, baseURI,
             XMLSignature.ALGO_ID_SIGNATURE_RSA);
doc.getFirstChild().appendChild(sig.getElement());

// Add fragment resolver for uri=""
ResolverFragment fragmentResolver = new ResolverFragment();
sig.addResourceResolver(fragmentResolver);

// Add transform for enveloped signature
Transforms transforms = new Transforms(doc);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);

// Set XPATH and adding as a transform
XPathContainer xpathContainer = new XPathContainer(doc);
xpathContainer.setXPathNamespaceContext("ds",
            Constants.SignatureSpecNS);

// Setting elements 'lastname' to be signed
String xpath = "/users/user/lastname";
xpathContainer.setXPath(xpath);
transforms.addTransform(Transforms.TRANSFORM_XPATH,
            xpathContainer.getElementPlusReturns());

// Setting 'to be signed' element
sig.addDocument("",transforms,Constants.ALGO_ID_DIGEST_SHA1);

// Adding data for verification
X509Certificate signerCert = (X509Certificate)
            ks.getCertificate(certificateAlias);
sig.addKeyInfo(signerCert);

// ..and finally sign it!
sig.sign(privateKey);

// Saving on a file
FileOutputStream fos = new FileOutputStream(signatureFile);
XMLUtils.outputDOM(doc,fos);
fos.close();


I have different versions of signed file:
1) the original (enveloped-signature.xml);
2) with altered signature (altered-enveloped-signature.xml, see MORDOR initial sequence instead of original sequence RdqK3K);
3) with one 'firstname' element content altered;
4) with one 'lastname' element content altered;

When I verify these four files, with the following code:

// loading signed file
File signatureFile = new File(...one of the four files...);
String baseURI = signatureFile.toURL().toString();

// parsing it
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setErrorHandler(new IgnoreAllErrorHandler());
Document signedDoc = db.parse(signatureFile);

// finding signature element
Element nsContext = XMLUtils.createDSctx(signedDoc, "ds",
                Constants.SignatureSpecNS);
Element signatureElement = (Element)
            XPathAPI.selectSingleNode(signedDoc,
                "//ds:Signature[1]",nsContext);
XMLSignature signature = new XMLSignature(signatureElement,baseURI);

ResolverFragment fragmentResolver = new ResolverFragment();
signature.addResourceResolver(fragmentResolver);

// Loading KeyInfo for verofying it KeyInfo ki = signature.getKeyInfo();
boolean result = signature.checkSignatureValue(ki.getX509Certificate());
// printing verification result
logger.info("Signature is " + (result ? "good" : "bad"));



I obtain these results:

1) 'Signature is good' (obviously)
2) 'Signature is bad' (right: the signature was altered)
3) 'Signature is bad' (wrong: I altered the content of one of the 'firstname' elements, but during signature I was specifying 'lastname' elements to be signed) 4) 'Signature is bad' (right: I altered the content of one of the 'lastname' elements)

If you see signatures and content digests, they are always the same, as if I hadn't specified an XPath to select portions of the document (wholedocument-enveloped-signature.xml is the same document signed as a whole).

What's wrong with my code?

Thanks

Daniele



--
-------------------------------------------
Daniele Gagliardi

Engiweb Security - Gruppo Engineering
Corso Stati Uniti 23/I
35127 Padova, Italia

Tel. ++39 0498692507
Fax. ++39 0498692566

http://www.engiweb.com

e-mail:   [EMAIL PROTECTED]
-------------------------------------------

Reply via email to