/*
* eID Applet Project.
* Copyright (C) 2009 FedICT.
* Copyright (C) 2014 e-Contract.be BVBA.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, see
* http://www.gnu.org/licenses/.
*/
/*
* Copyright (C) 2009 FedICT.
* This file is part of the eID Applet Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package test.unit.be.fedict.eid.applet.service.signer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import javax.crypto.Cipher;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.joda.time.DateTime;
import org.junit.BeforeClass;
import org.junit.Test;
import be.fedict.eid.applet.service.signer.DigestAlgo;
import be.fedict.eid.applet.service.signer.TemporaryDataStorage;
import be.fedict.eid.applet.service.signer.ooxml.AbstractOOXMLSignatureService;
import be.fedict.eid.applet.service.signer.ooxml.OOXMLProvider;
import be.fedict.eid.applet.service.signer.ooxml.OOXMLSignatureVerifier;
import be.fedict.eid.applet.service.spi.DigestInfo;
public class AbstractOOXMLSignatureServiceTest {
private static final Log LOG = LogFactory.getLog(AbstractOOXMLSignatureServiceTest.class);
@BeforeClass
public static void setUp() {
OOXMLProvider.install();
}
private static class OOXMLTestSignatureService extends AbstractOOXMLSignatureService {
private final URL ooxmlUrl;
private final TemporaryTestDataStorage temporaryDataStorage;
private final ByteArrayOutputStream signedOOXMLOutputStream;
public OOXMLTestSignatureService(URL ooxmlUrl) {
super(DigestAlgo.SHA1);
this.temporaryDataStorage = new TemporaryTestDataStorage();
this.signedOOXMLOutputStream = new ByteArrayOutputStream();
this.ooxmlUrl = ooxmlUrl;
}
@Override
protected URL getOfficeOpenXMLDocumentURL() {
return this.ooxmlUrl;
}
@Override
protected OutputStream getSignedOfficeOpenXMLDocumentOutputStream() {
return this.signedOOXMLOutputStream;
}
public byte[] getSignedOfficeOpenXMLDocumentData() {
return this.signedOOXMLOutputStream.toByteArray();
}
@Override
protected TemporaryDataStorage getTemporaryDataStorage() {
return this.temporaryDataStorage;
}
}
@Test
public void testPreSign() throws Exception {
// setup
URL ooxmlUrl = AbstractOOXMLSignatureServiceTest.class.getResource("/hello-world-unsigned.docx");
assertNotNull(ooxmlUrl);
OOXMLTestSignatureService signatureService = new OOXMLTestSignatureService(ooxmlUrl);
KeyPair keyPair = PkiTestUtils.generateKeyPair();
DateTime notBefore = new DateTime();
DateTime notAfter = notBefore.plusYears(1);
X509Certificate certificate = PkiTestUtils.generateCertificate(keyPair.getPublic(), "CN=Test", notBefore,
notAfter, null, keyPair.getPrivate(), true, 0, null, null, new KeyUsage(KeyUsage.nonRepudiation));
// operate
DigestInfo digestInfo = signatureService.preSign(null, Collections.singletonList(certificate), null, null,
null);
// verify
assertNotNull(digestInfo);
LOG.debug("digest algo: " + digestInfo.digestAlgo);
LOG.debug("digest description: " + digestInfo.description);
assertEquals("Office OpenXML Document", digestInfo.description);
assertNotNull(digestInfo.digestAlgo);
assertNotNull(digestInfo.digestValue);
TemporaryDataStorage temporaryDataStorage = signatureService.getTemporaryDataStorage();
String preSignResult = IOUtils.toString(temporaryDataStorage.getTempInputStream());
LOG.debug("pre-sign result: " + preSignResult);
File tmpFile = File.createTempFile("ooxml-pre-sign-", ".xml");
FileUtils.writeStringToFile(tmpFile, preSignResult);
LOG.debug("tmp pre-sign file: " + tmpFile.getAbsolutePath());
}
@Test
public void testPostSign() throws Exception {
sign("/hello-world-unsigned.docx");
}
@Test
public void testSignOffice2010TechnicalPreview() throws Exception {
sign("/hello-world-office-2010-technical-preview-unsigned.docx");
}
@Test
public void testSignOffice2010() throws Exception {
sign("/ms-office-2010.docx");
}
@Test
public void testHyperlinkExample() throws Exception {
sign("/hyperlink-example.docx");
}
@Test
public void testSignTwice() throws Exception {
sign("/hello-world-signed.docx", 2);
}
@Test
public void testSignTwiceHere() throws Exception {
File tmpFile = sign("/hello-world-unsigned.docx", 1);
sign(tmpFile.toURI().toURL(), "CN=Test2", 2);
}
@Test
public void testSignPowerpoint() throws Exception {
sign("/hello-world-unsigned.pptx");
}
@Test
public void testSignSpreadsheet() throws Exception {
sign("/hello-world-unsigned.xlsx");
}
private void sign(String documentResourceName) throws Exception {
sign(documentResourceName, 1);
}
private File sign(String documentResourceName, int signerCount) throws Exception {
URL ooxmlUrl = AbstractOOXMLSignatureServiceTest.class.getResource(documentResourceName);
return sign(ooxmlUrl, signerCount);
}
private File sign(URL ooxmlUrl, int signerCount) throws Exception {
return sign(ooxmlUrl, "CN=Test", signerCount);
}
private File sign(URL ooxmlUrl, String signerDn, int signerCount) throws Exception {
// setup
assertNotNull(ooxmlUrl);
OOXMLTestSignatureService signatureService = new OOXMLTestSignatureService(ooxmlUrl);
KeyPair keyPair = PkiTestUtils.generateKeyPair();
DateTime notBefore = new DateTime();
DateTime notAfter = notBefore.plusYears(1);
X509Certificate certificate = PkiTestUtils.generateCertificate(keyPair.getPublic(), signerDn, notBefore,
notAfter, null, keyPair.getPrivate(), true, 0, null, null, new KeyUsage(KeyUsage.digitalSignature));
// operate
DigestInfo digestInfo = signatureService.preSign(null, Collections.singletonList(certificate), null, null,
null);
// verify
assertNotNull(digestInfo);
LOG.debug("digest algo: " + digestInfo.digestAlgo);
LOG.debug("digest description: " + digestInfo.description);
assertEquals("Office OpenXML Document", digestInfo.description);
assertNotNull(digestInfo.digestAlgo);
assertNotNull(digestInfo.digestValue);
TemporaryDataStorage temporaryDataStorage = signatureService.getTemporaryDataStorage();
String preSignResult = IOUtils.toString(temporaryDataStorage.getTempInputStream());
LOG.debug("pre-sign result: " + preSignResult);
File tmpFile = File.createTempFile("ooxml-pre-sign-", ".xml");
FileUtils.writeStringToFile(tmpFile, preSignResult);
LOG.debug("tmp pre-sign file: " + tmpFile.getAbsolutePath());
// setup: key material, signature value
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
byte[] digestInfoValue = ArrayUtils.addAll(PkiTestUtils.SHA1_DIGEST_INFO_PREFIX, digestInfo.digestValue);
byte[] signatureValue = cipher.doFinal(digestInfoValue);
// operate: postSign
signatureService.postSign(signatureValue, Collections.singletonList(certificate));
// verify: signature
byte[] signedOOXMLData = signatureService.getSignedOfficeOpenXMLDocumentData();
assertNotNull(signedOOXMLData);
LOG.debug("signed OOXML size: " + signedOOXMLData.length);
String extension = FilenameUtils.getExtension(ooxmlUrl.getFile());
tmpFile = File.createTempFile("ooxml-signed-", "." + extension);
FileUtils.writeByteArrayToFile(tmpFile, signedOOXMLData);
LOG.debug("signed OOXML file: " + tmpFile.getAbsolutePath());
OOXMLSignatureVerifier verifier = new OOXMLSignatureVerifier();
List<X509Certificate> signers = verifier.getSigners(tmpFile.toURI().toURL());
assertEquals(signerCount, signers.size());
// assertEquals(certificate, signers.get(0));
LOG.debug("signed OOXML file: " + tmpFile.getAbsolutePath());
return tmpFile;
}
}