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]
-------------------------------------------