2 /* ====================================================================
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================== */
20 * Based on the eID Applet Project code.
21 * Original Copyright (C) 2008-2009 FedICT.
24 package org.apache.poi.ooxml.signature.service.signer;
26 import java.io.ByteArrayOutputStream;
28 import java.io.OutputStream;
30 import java.security.KeyPair;
31 import java.security.cert.X509Certificate;
32 import java.util.Collections;
33 import java.util.List;
35 import javax.crypto.Cipher;
37 import junit.framework.TestCase;
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.io.FilenameUtils;
41 import org.apache.commons.io.IOUtils;
42 import org.apache.commons.lang.ArrayUtils;
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45 import org.apache.poi.ooxml.signature.service.signer.TemporaryDataStorage;
46 import org.apache.poi.ooxml.signature.service.signer.ooxml.AbstractOOXMLSignatureService;
47 import org.apache.poi.ooxml.signature.service.signer.ooxml.OOXMLProvider;
48 import org.apache.poi.ooxml.signature.service.signer.ooxml.OOXMLSignatureVerifier;
49 import org.apache.poi.ooxml.signature.service.spi.DigestInfo;
50 import org.bouncycastle.asn1.x509.KeyUsage;
51 import org.joda.time.DateTime;
55 public class TestAbstractOOXMLSignatureService extends TestCase {
57 private static final Log LOG = LogFactory.getLog(TestAbstractOOXMLSignatureService.class);
60 OOXMLProvider.install();
63 private static class OOXMLTestSignatureService extends AbstractOOXMLSignatureService {
65 private final URL ooxmlUrl;
67 private final TemporaryTestDataStorage temporaryDataStorage;
69 private final ByteArrayOutputStream signedOOXMLOutputStream;
71 public OOXMLTestSignatureService(URL ooxmlUrl) {
72 this.temporaryDataStorage = new TemporaryTestDataStorage();
73 this.signedOOXMLOutputStream = new ByteArrayOutputStream();
74 this.ooxmlUrl = ooxmlUrl;
78 protected URL getOfficeOpenXMLDocumentURL() {
83 protected OutputStream getSignedOfficeOpenXMLDocumentOutputStream() {
84 return this.signedOOXMLOutputStream;
87 public byte[] getSignedOfficeOpenXMLDocumentData() {
88 return this.signedOOXMLOutputStream.toByteArray();
92 protected TemporaryDataStorage getTemporaryDataStorage() {
93 return this.temporaryDataStorage;
97 public void testPreSign() throws Exception {
99 URL ooxmlUrl = TestAbstractOOXMLSignatureService.class.getResource("/hello-world-unsigned.docx");
100 assertNotNull(ooxmlUrl);
102 OOXMLTestSignatureService signatureService = new OOXMLTestSignatureService(ooxmlUrl);
105 DigestInfo digestInfo = signatureService.preSign(null, null);
108 assertNotNull(digestInfo);
109 LOG.debug("digest algo: " + digestInfo.digestAlgo);
110 LOG.debug("digest description: " + digestInfo.description);
111 assertEquals("Office OpenXML Document", digestInfo.description);
112 assertNotNull(digestInfo.digestAlgo);
113 assertNotNull(digestInfo.digestValue);
115 TemporaryDataStorage temporaryDataStorage = signatureService.getTemporaryDataStorage();
116 String preSignResult = IOUtils.toString(temporaryDataStorage.getTempInputStream());
117 LOG.debug("pre-sign result: " + preSignResult);
118 File tmpFile = File.createTempFile("ooxml-pre-sign-", ".xml");
119 FileUtils.writeStringToFile(tmpFile, preSignResult);
120 LOG.debug("tmp pre-sign file: " + tmpFile.getAbsolutePath());
123 public void testPostSign() throws Exception {
124 sign("/hello-world-unsigned.docx");
127 public void testSignOffice2010() throws Exception {
128 sign("/hello-world-office-2010-technical-preview-unsigned.docx");
131 public void testSignTwice() throws Exception {
132 sign("/hello-world-signed.docx", 2);
135 public void testSignTwiceHere() throws Exception {
136 File tmpFile = sign("/hello-world-unsigned.docx", 1);
137 sign(tmpFile.toURI().toURL(), "CN=Test2", 2);
140 public void testSignPowerpoint() throws Exception {
141 sign("/hello-world-unsigned.pptx");
144 public void testSignSpreadsheet() throws Exception {
145 sign("/hello-world-unsigned.xlsx");
148 private void sign(String documentResourceName) throws Exception {
149 sign(documentResourceName, 1);
152 private File sign(String documentResourceName, int signerCount) throws Exception {
153 URL ooxmlUrl = TestAbstractOOXMLSignatureService.class.getResource(documentResourceName);
154 return sign(ooxmlUrl, signerCount);
157 private File sign(URL ooxmlUrl, int signerCount) throws Exception {
158 return sign(ooxmlUrl, "CN=Test", signerCount);
161 private File sign(URL ooxmlUrl, String signerDn, int signerCount) throws Exception {
163 assertNotNull(ooxmlUrl);
165 OOXMLTestSignatureService signatureService = new OOXMLTestSignatureService(ooxmlUrl);
168 DigestInfo digestInfo = signatureService.preSign(null, null);
171 assertNotNull(digestInfo);
172 LOG.debug("digest algo: " + digestInfo.digestAlgo);
173 LOG.debug("digest description: " + digestInfo.description);
174 assertEquals("Office OpenXML Document", digestInfo.description);
175 assertNotNull(digestInfo.digestAlgo);
176 assertNotNull(digestInfo.digestValue);
178 TemporaryDataStorage temporaryDataStorage = signatureService.getTemporaryDataStorage();
179 String preSignResult = IOUtils.toString(temporaryDataStorage.getTempInputStream());
180 LOG.debug("pre-sign result: " + preSignResult);
181 File tmpFile = File.createTempFile("ooxml-pre-sign-", ".xml");
182 FileUtils.writeStringToFile(tmpFile, preSignResult);
183 LOG.debug("tmp pre-sign file: " + tmpFile.getAbsolutePath());
185 // setup: key material, signature value
186 KeyPair keyPair = PkiTestUtils.generateKeyPair();
187 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
188 cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
189 byte[] digestInfoValue = ArrayUtils.addAll(PkiTestUtils.SHA1_DIGEST_INFO_PREFIX, digestInfo.digestValue);
190 byte[] signatureValue = cipher.doFinal(digestInfoValue);
192 DateTime notBefore = new DateTime();
193 DateTime notAfter = notBefore.plusYears(1);
194 X509Certificate certificate = PkiTestUtils.generateCertificate(keyPair.getPublic(), signerDn, notBefore, notAfter, null, keyPair.getPrivate(), true, 0,
195 null, null, new KeyUsage(KeyUsage.nonRepudiation));
198 signatureService.postSign(signatureValue, Collections.singletonList(certificate));
201 byte[] signedOOXMLData = signatureService.getSignedOfficeOpenXMLDocumentData();
202 assertNotNull(signedOOXMLData);
203 LOG.debug("signed OOXML size: " + signedOOXMLData.length);
204 String extension = FilenameUtils.getExtension(ooxmlUrl.getFile());
205 tmpFile = File.createTempFile("ooxml-signed-", "." + extension);
206 FileUtils.writeByteArrayToFile(tmpFile, signedOOXMLData);
207 LOG.debug("signed OOXML file: " + tmpFile.getAbsolutePath());
208 List<X509Certificate> signers = OOXMLSignatureVerifier.getSigners(tmpFile.toURI().toURL());
209 assertEquals(signerCount, signers.size());
210 // assertEquals(certificate, signers.get(0));
211 LOG.debug("signed OOXML file: " + tmpFile.getAbsolutePath());