Hi Colm,
run the code below w/ doFinalTransform true or false to see the difference...
when transform is true, you will see the sig block found:
----/aaa/Signature----
num nodes = 1
Signature
null
but w/ transform false, you will see not found:
----/aaa/Signature----
num nodes = 0
I have combined code from a few different classes here to simplify things:
public void signAndDoXpaths2()
throws Exception
{
boolean doFinalTransform = true;
String certFileName = "testcert.p12";
String certPw = "123456";
String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<aaa>" +
" <bbb>PD94bWwgdm</bbb>" +
"</aaa>";
DocumentBuilderFactory docFactory =
DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware( false );
DocumentBuilder builder = docFactory.newDocumentBuilder();
Document doc = builder.parse( new ByteArrayInputStream(
xml.getBytes() ) );
XMLSignatureFactory fac = XMLSignatureFactory.getInstance
("DOM");
Reference ref = fac.newReference
("", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform
(Transform.ENVELOPED, (TransformParameterSpec) null)),
null, null);
// Create the SignedInfo.
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod( SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
if (Security.getProvider("BC") == null)
{
Security.addProvider( new
org.bouncycastle.jce.provider.BouncyCastleProvider() );
}
KeyStore ks = null;
ks = KeyStore.getInstance( "PKCS12", "BC" );
File certFile = new File( certFileName );
ks.load( new FileInputStream( certFile ), certPw.toCharArray
() );
String keyAlias = (String) ks.aliases().nextElement();
X509Certificate cert = null;
KeyStore.PrivateKeyEntry keyEntry = null;
keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry
(
keyAlias,
new KeyStore.PasswordProtection(
certPw.toCharArray() )
);
cert = (X509Certificate) keyEntry.getCertificate();
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey
(), doc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
// Output the resulting document - this seems to be a critical
step that allows
// stuff like xpaths to work
if ( doFinalTransform == true )
{
byte[] outputData = new byte[ 10000 ];
ByteArrayOutputStream baos = new ByteArrayOutputStream
();
TransformerFactory tf = TransformerFactory.newInstance
();
Transformer trans = tf.newTransformer();
trans.transform( new DOMSource(doc), new StreamResult(
baos ) );
String signedString = baos.toString();
ByteArrayInputStream bais = new ByteArrayInputStream(
signedString.getBytes() );
doc = docFactory.newDocumentBuilder().parse( bais );
}
System.out.println( "xml signed successfully");
System.out.println( "xml:\n" + convertDocToString( doc ) );
String[] xpathList = new String[]
{
"/aaa/Signature",
"/aaa/Signature/SignedInfo/Reference/DigestValue/text
()",
"/aaa/Signature/SignatureValue/text()",
"/aaa/Signature/KeyInfo/X509Data/X509Certificate/text
()",
"/aaa/ns:Signature",
};
for ( String xPathFromList : xpathList )
{
if ( xPathFromList.contains( "substring" ) ||
xPathFromList.contains( "concat" ) )
executeXPath( doc, xPathFromList,
XPathConstants.STRING, null );
else
executeXPath( doc, xPathFromList,
XPathConstants.NODESET, null );
}
}
public Object executeXPath( Document doc, String strExpr, QName
xpathConstant,
NamespaceContext nsCtx ) throws Exception
{
Object result = null;
System.out.println( "----" + strExpr + "----" );
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
if ( nsCtx != null )
xpath.setNamespaceContext( nsCtx );
XPathExpression expr = xpath.compile( strExpr );
if ( xpathConstant.equals( XPathConstants.NODESET ) )
{
result = expr.evaluate( doc, xpathConstant /*
XPathConstants.NODESET */ );
NodeList nodes = (NodeList) result;
int len = nodes.getLength();
System.out.println( "num nodes = " + len );
for (int i = 0; i < nodes.getLength(); i++)
{
System.out.println( nodes.item( i ).getNodeName
() );
System.out.println( nodes.item( i ).getNodeValue
() );
//System.out.println( nodes.item( i ).getBaseURI
() );
//nodes.item( i ).get
}
}
else if ( xpathConstant.equals( XPathConstants.NUMBER ) )
{
result = expr.evaluate( doc,
xpathConstant /*XPathConstants.NUMBER */ );
double dResult = Double.parseDouble( result.toString
() );
System.out.println( "number = " + dResult );
}
else if ( xpathConstant.equals( XPathConstants.STRING ) )
{
result = expr.evaluate( doc, xpathConstant );
String str = result.toString();
System.out.println( "string = " + str );
}
System.out.println( "-----------------" );
return result;
}
private String convertDocToString( Document doc )
{
try
{
DOMSource domSource = new DOMSource( doc );
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult( writer );
TransformerFactory tf = TransformerFactory.newInstance
();
Transformer transformer = tf.newTransformer();
transformer.transform( domSource, result );
writer.flush();
return writer.toString();
}
catch ( TransformerException ex )
{
ex.printStackTrace();
return null;
}
}