package com.zenika.xml.signature.builder;
import com.zenika.xml.signature.XmlSignatureBuilder;
import com.zenika.xml.signature.validation.AdvancedKeySelector;
import com.zenika.xml.signature.validation.HashKeySelector;
import com.zenika.xml.signature.validation.XmlSignatureValidationFactory;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.logging.Logger;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* XmlSignatureBuilder & XmlSignatureValidation testing for 3 signature modes (enveloped, enveloping and detached)
*/
public class XmlSignatureBuilderTest {
private static final Logger LOGGER = Logger.getLogger(XmlSignatureBuilderTest.class.getSimpleName());
private Certificate certificate;
private KeyStore keyStore;
private PrivateKey privateKey;
private PublicKey publicKey;
private Transformer transformer;
private DocumentBuilder documentBuilder;
private Document document1;
private Document document2;
private AdvancedKeySelector keySelector;
public XmlSignatureBuilderTest() throws TransformerConfigurationException, KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
documentBuilder = documentBuilderFactory.newDocumentBuilder();
transformer = TransformerFactory.newInstance().newTransformer();
// load private key
InputStream keyStoreStream = this.getClass().getResourceAsStream("/keystore.jks");
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyStoreStream, "zenika".toCharArray());
privateKey = (PrivateKey) keyStore.getKey("zenika", "zenika".toCharArray());
certificate = keyStore.getCertificate("zenika");
publicKey = certificate.getPublicKey();
keySelector = new HashKeySelector(keyStore);
}
@Before
public void before() throws ParserConfigurationException, IOException, SAXException {
// load doc1
InputStream resourceAsStream = this.getClass().getResourceAsStream("/doc1.xml");
document1 = documentBuilder.parse(resourceAsStream);
//load doc2
resourceAsStream = this.getClass().getResourceAsStream("/doc2.xml");
document2 = documentBuilder.parse(resourceAsStream);
}
@Test
public void testEnvelopedSignature() throws ParserConfigurationException, IOException, SAXException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, XMLSignatureException, MarshalException, CertificateException, TransformerException {
LOGGER.info("ENVELOPED SIGNATURE");
Document result = new XmlSignatureBuilder().
withKeyInfo().
withKeyName(certificate, keySelector.getKeyNameFunction()).
buildAndAttach().
withSignedInfo().
withExclusiveCanonicalization().
withRsaSha256Signature().
withReference().
withEnvelopedTransformation().
withSHA256Digest().
buildAndAttach().
buildAndAttach().
buildAndSign(privateKey, document1);
printDocument(result);
validateWithKeySelector(result);
}
@Test
public void testEnvelopingSignature() throws ParserConfigurationException, IOException, SAXException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, XMLSignatureException, MarshalException, CertificateException, TransformerException, KeyException {
LOGGER.info("ENVELOPING SIGNATURE");
Document result = new XmlSignatureBuilder().
withKeyInfo().
withKeyName(certificate, keySelector.getKeyNameFunction()).
buildAndAttach().
withSignedInfo().
withExclusiveCanonicalization().
withRsaSha256Signature().
withReference().
withURI("#doc1").
withSHA256Digest().
withExclusiveCanonicalization().
buildAndAttach().
withReference().
withURI("#doc2").
withSHA1Digest().
withExclusiveCanonicalization().
buildAndAttach().
buildAndAttach().
withObject(document1.getDocumentElement(), "doc1").
withObject(document2.getDocumentElement(), "doc2").
buildAndSign(privateKey);
printDocument(result);
validateWithKeySelector(result);
}
@Test
public void testDetachedSignature() throws ParserConfigurationException, IOException, SAXException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, XMLSignatureException, MarshalException, CertificateException, TransformerException, KeyException {
LOGGER.info("DETACHED SIGNATURE");
Document result = new XmlSignatureBuilder().
withKeyInfo().
withPublicKey(publicKey).
buildAndAttach().
withSignedInfo().
withExclusiveCanonicalization().
withRsaSha256Signature().
withReference().
withURI("http://www.w3schools.com/xml/note.xml").
withSHA256Digest().
buildAndAttach().
buildAndAttach().
buildAndSign(privateKey);
printDocument(result);
validateWithPublicKey(result);
}
private void validateWithKeySelector(Document document) throws MarshalException, XMLSignatureException {
assertTrue(XmlSignatureValidationFactory.
fromKeySelector(keySelector).
validate(document));
}
private void validateWithPublicKey(Document document) throws MarshalException, XMLSignatureException {
assertTrue(XmlSignatureValidationFactory.
fromPublicKey(publicKey).
validate(document));
}
private void printDocument(Document document) throws TransformerException {
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(writer));
LOGGER.info(writer.toString());
}
}