/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.core.util.xml; import java.io.File; import java.net.URL; import java.nio.file.Files; import org.junit.Assert; import org.junit.Test; import org.olat.core.util.FileUtils; import org.olat.core.util.crypto.CryptoUtil; import org.olat.core.util.crypto.X509CertificatePrivateKeyPair; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * Initial date: 16 févr. 2017<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class XMLDigitalSignatureUtilTest { /** * Check if the cycle sign -> validation works * * @throws Exception */ @Test public void signDetachedAndValidate() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); String xmlUri = xmlUrl.toURI().toString(); File xmlSignatureFile = File.createTempFile("assessment-result", "_signature.xml"); XMLDigitalSignatureUtil.signDetached(xmlUri, xmlFile, xmlSignatureFile, null, null, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignatureFile.length() > 0); boolean valid = XMLDigitalSignatureUtil.validate(xmlUri, xmlFile, xmlSignatureFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertTrue(valid); //clean up Files.deleteIfExists(xmlSignatureFile.toPath()); } @Test public void signDetachedAndValidate_exoticUri() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); String xmlUri = "http://localhost:8081/RepositoryEntry/688455680/CourseNode/95133178953589/TestSession/2693/assessmentResult.xml"; File xmlSignatureFile = File.createTempFile("assessment-result", "_signature.xml"); XMLDigitalSignatureUtil.signDetached(xmlUri, xmlFile, xmlSignatureFile, null, null, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignatureFile.length() > 0); boolean valid = XMLDigitalSignatureUtil.validate(xmlUri, xmlFile, xmlSignatureFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertTrue(valid); //clean up Files.deleteIfExists(xmlSignatureFile.toPath()); } /** * Test if the signature can be detached and imported in an other * DOM structure. * * @throws Exception */ @Test public void signDetachedAndValidate_containSignatureDocument() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); String xmlUri = "http://localhost:8081/RepositoryEntry/688455680/CourseNode/95133178953589/TestSession/2693/assessmentResult.xml"; Document signatureDocument = XMLDigitalSignatureUtil.createDocument(); Node rootNode = signatureDocument.appendChild(signatureDocument.createElement("assessmentTestSignature")); Node courseNode = rootNode.appendChild(signatureDocument.createElement("course")); courseNode.appendChild(signatureDocument.createTextNode("Very difficult test")); File xmlSignatureFile = File.createTempFile("assessment-result", "_signature.xml"); XMLDigitalSignatureUtil.signDetached(xmlUri, xmlFile, xmlSignatureFile, signatureDocument, null, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignatureFile.length() > 0); boolean valid = XMLDigitalSignatureUtil.validate(xmlUri, xmlFile, xmlSignatureFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertTrue(valid); //load the signature and check that the course info and the Signature is there Document reloadSignatureDocument = XMLDigitalSignatureUtil.getDocument(xmlSignatureFile); NodeList courseNl = reloadSignatureDocument.getElementsByTagName("course"); Assert.assertEquals(1, courseNl.getLength()); NodeList signatureNl = reloadSignatureDocument.getElementsByTagName("Signature"); Assert.assertEquals(1, signatureNl.getLength()); //clean up Files.deleteIfExists(xmlSignatureFile.toPath()); } @Test public void signDetachedAndValidate_notValid() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); String xmlUri = xmlUrl.toURI().toString(); File xmlSignatureFile = File.createTempFile("assessment-result", "_signature.xml"); XMLDigitalSignatureUtil.signDetached(xmlUri, xmlFile, xmlSignatureFile, null, null, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignatureFile.length() > 0); URL xmlTamperedUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult_tampered.xml"); File xmlTamperedFile = new File(xmlTamperedUrl.toURI()); boolean valid = XMLDigitalSignatureUtil.validate(xmlUri, xmlTamperedFile, xmlSignatureFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertFalse(valid); //clean up Files.deleteIfExists(xmlSignatureFile.toPath()); } @Test public void signAndValidate() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); File xmlSignedFile = File.createTempFile("assessment-result", "_signed.xml"); XMLDigitalSignatureUtil.signEmbedded(xmlFile, xmlSignedFile, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignedFile.length() > 0); boolean valid = XMLDigitalSignatureUtil.validate(xmlSignedFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertTrue(valid); //clean up Files.deleteIfExists(xmlSignedFile.toPath()); } /** * Check that the signature validate the data too by slightly changing a value in * the signed XML file. * * * @throws Exception */ @Test public void signAndValidate_notValid() throws Exception { X509CertificatePrivateKeyPair certificateInfo = getCertificatePrivateKeyPair(); URL xmlUrl = XMLDigitalSignatureUtilTest.class.getResource("assessmentResult.xml"); File xmlFile = new File(xmlUrl.toURI()); File xmlSignedFile = File.createTempFile("assessment-result", "_signed.xml"); XMLDigitalSignatureUtil.signEmbedded(xmlFile, xmlSignedFile, certificateInfo.getX509Cert(), certificateInfo.getPrivateKey()); Assert.assertTrue(xmlSignedFile.length() > 0); //the xml is signed and valid boolean valid = XMLDigitalSignatureUtil.validate(xmlSignedFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertTrue(valid); //change it a little bit String xml = FileUtils.load(xmlSignedFile, "UTF-8"); String rogueXml = xml.replace("test7501c21c-c3db-468d-b5b8-c40339aaf323.xml", "test7501c21c-468d-b5b8-c40339aaf323.xml"); Assert.assertNotEquals(xml, rogueXml); File xmlRogueFile = File.createTempFile("assessment-result", "_rogue.xml"); FileUtils.save(xmlRogueFile, rogueXml, "UTF-8"); //the xml is not valid boolean validity = XMLDigitalSignatureUtil.validate(xmlRogueFile, certificateInfo.getX509Cert().getPublicKey()); Assert.assertFalse(validity); //clean up Files.deleteIfExists(xmlSignedFile.toPath()); Files.deleteIfExists(xmlRogueFile.toPath()); } private X509CertificatePrivateKeyPair getCertificatePrivateKeyPair() throws Exception { URL certificateUrl = XMLDigitalSignatureUtilTest.class.getResource("certificate.pfx"); File certificate = new File(certificateUrl.toURI()); return CryptoUtil.getX509CertificatePrivateKeyPairPfx(certificate, ""); } }