You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestSignatureInfo.java 53KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. /* ====================================================================
  16. This product contains an ASLv2 licensed version of the OOXML signer
  17. package from the eID Applet project
  18. http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
  19. Copyright (C) 2008-2014 FedICT.
  20. ================================================================= */
  21. package org.apache.poi.poifs.crypt;
  22. import static org.junit.Assert.assertEquals;
  23. import static org.junit.Assert.assertFalse;
  24. import static org.junit.Assert.assertNotNull;
  25. import static org.junit.Assert.assertTrue;
  26. import static org.junit.Assume.assumeTrue;
  27. import java.io.BufferedReader;
  28. import java.io.ByteArrayInputStream;
  29. import java.io.ByteArrayOutputStream;
  30. import java.io.File;
  31. import java.io.FileInputStream;
  32. import java.io.FileOutputStream;
  33. import java.io.IOException;
  34. import java.io.InputStream;
  35. import java.io.InputStreamReader;
  36. import java.io.OutputStream;
  37. import java.math.BigInteger;
  38. import java.net.ConnectException;
  39. import java.net.HttpURLConnection;
  40. import java.net.MalformedURLException;
  41. import java.net.SocketTimeoutException;
  42. import java.net.URL;
  43. import java.nio.charset.StandardCharsets;
  44. import java.security.Key;
  45. import java.security.KeyPair;
  46. import java.security.KeyPairGenerator;
  47. import java.security.KeyStore;
  48. import java.security.PrivateKey;
  49. import java.security.PublicKey;
  50. import java.security.SecureRandom;
  51. import java.security.cert.CRLException;
  52. import java.security.cert.Certificate;
  53. import java.security.cert.CertificateEncodingException;
  54. import java.security.cert.CertificateException;
  55. import java.security.cert.X509CRL;
  56. import java.security.cert.X509Certificate;
  57. import java.security.interfaces.RSAPublicKey;
  58. import java.security.spec.RSAKeyGenParameterSpec;
  59. import java.util.ArrayList;
  60. import java.util.Calendar;
  61. import java.util.Collections;
  62. import java.util.Date;
  63. import java.util.Iterator;
  64. import java.util.List;
  65. import javax.xml.crypto.MarshalException;
  66. import javax.xml.crypto.dsig.CanonicalizationMethod;
  67. import javax.xml.crypto.dsig.XMLSignatureException;
  68. import javax.xml.crypto.dsig.dom.DOMSignContext;
  69. import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
  70. import org.apache.poi.EncryptedDocumentException;
  71. import org.apache.poi.POIDataSamples;
  72. import org.apache.poi.POITestCase;
  73. import org.apache.poi.ooxml.util.DocumentHelper;
  74. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  75. import org.apache.poi.openxml4j.opc.OPCPackage;
  76. import org.apache.poi.openxml4j.opc.PackageAccess;
  77. import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
  78. import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
  79. import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
  80. import org.apache.poi.poifs.crypt.dsig.SignaturePart;
  81. import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
  82. import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
  83. import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
  84. import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
  85. import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
  86. import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
  87. import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
  88. import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
  89. import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
  90. import org.apache.poi.poifs.storage.RawDataUtil;
  91. import org.apache.poi.ss.usermodel.WorkbookFactory;
  92. import org.apache.poi.util.IOUtils;
  93. import org.apache.poi.util.LocaleUtil;
  94. import org.apache.poi.util.POILogFactory;
  95. import org.apache.poi.util.POILogger;
  96. import org.apache.poi.xssf.streaming.SXSSFWorkbook;
  97. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  98. import org.apache.xmlbeans.SystemProperties;
  99. import org.apache.xmlbeans.XmlObject;
  100. import org.bouncycastle.asn1.DERIA5String;
  101. import org.bouncycastle.asn1.DEROctetString;
  102. import org.bouncycastle.asn1.DERSequence;
  103. import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
  104. import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  105. import org.bouncycastle.asn1.x500.X500Name;
  106. import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
  107. import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
  108. import org.bouncycastle.asn1.x509.BasicConstraints;
  109. import org.bouncycastle.asn1.x509.CRLNumber;
  110. import org.bouncycastle.asn1.x509.CRLReason;
  111. import org.bouncycastle.asn1.x509.DistributionPoint;
  112. import org.bouncycastle.asn1.x509.DistributionPointName;
  113. import org.bouncycastle.asn1.x509.Extension;
  114. import org.bouncycastle.asn1.x509.Extensions;
  115. import org.bouncycastle.asn1.x509.GeneralName;
  116. import org.bouncycastle.asn1.x509.GeneralNames;
  117. import org.bouncycastle.asn1.x509.KeyUsage;
  118. import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
  119. import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  120. import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
  121. import org.bouncycastle.cert.X509CRLHolder;
  122. import org.bouncycastle.cert.X509CertificateHolder;
  123. import org.bouncycastle.cert.X509ExtensionUtils;
  124. import org.bouncycastle.cert.X509v2CRLBuilder;
  125. import org.bouncycastle.cert.X509v3CertificateBuilder;
  126. import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
  127. import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
  128. import org.bouncycastle.cert.ocsp.BasicOCSPResp;
  129. import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
  130. import org.bouncycastle.cert.ocsp.CertificateID;
  131. import org.bouncycastle.cert.ocsp.CertificateStatus;
  132. import org.bouncycastle.cert.ocsp.OCSPReq;
  133. import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
  134. import org.bouncycastle.cert.ocsp.OCSPResp;
  135. import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
  136. import org.bouncycastle.cert.ocsp.Req;
  137. import org.bouncycastle.cert.ocsp.RevokedStatus;
  138. import org.bouncycastle.crypto.params.RSAKeyParameters;
  139. import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
  140. import org.bouncycastle.openssl.PEMParser;
  141. import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
  142. import org.bouncycastle.operator.ContentSigner;
  143. import org.bouncycastle.operator.DigestCalculator;
  144. import org.bouncycastle.operator.OperatorCreationException;
  145. import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  146. import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
  147. import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
  148. import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
  149. import org.junit.AfterClass;
  150. import org.junit.Assume;
  151. import org.junit.BeforeClass;
  152. import org.junit.Ignore;
  153. import org.junit.Test;
  154. import org.w3.x2000.x09.xmldsig.ReferenceType;
  155. import org.w3.x2000.x09.xmldsig.SignatureDocument;
  156. import org.w3c.dom.Document;
  157. public class TestSignatureInfo {
  158. private static final POILogger LOG = POILogFactory.getLogger(TestSignatureInfo.class);
  159. private static final POIDataSamples testdata = POIDataSamples.getXmlDSignInstance();
  160. private static Calendar cal;
  161. private KeyPair keyPair;
  162. private X509Certificate x509;
  163. @AfterClass
  164. public static void removeUserLocale() {
  165. LocaleUtil.resetUserLocale();
  166. }
  167. @BeforeClass
  168. public static void initBouncy() {
  169. CryptoFunctions.registerBouncyCastle();
  170. // Set cal to now ... only set to fixed date for debugging ...
  171. LocaleUtil.resetUserLocale();
  172. LocaleUtil.resetUserTimeZone();
  173. cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
  174. assertNotNull(cal);
  175. // don't run this test when we are using older Xerces as it triggers an XML Parser backwards compatibility issue
  176. // in the xmlsec jar file
  177. String additionalJar = System.getProperty("additionaljar");
  178. //System.out.println("Having: " + additionalJar);
  179. Assume.assumeTrue("Not running TestSignatureInfo because we are testing with additionaljar set to " + additionalJar,
  180. additionalJar == null || additionalJar.trim().length() == 0);
  181. System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
  182. // Set line.separator for bug61182
  183. // System.setProperty("line.separator", "\n");
  184. }
  185. @Ignore("This test is very sensitive, it breaks with every little change to the produced XML")
  186. @Test
  187. public void bug61182() throws Exception {
  188. String pfxInput =
  189. "H4sIAAAAAAAAAFXTfzzTeRwH8P2uGRmG6hKSmJh9a2HsuPy60VnHCEU6v86sieZH2Jr2qFl+s+ZHJ5tfUcfKb4uho/OjiFq1qTv5ceFyp0PqEK"+
  190. "fH4+66++Pz+Dwer9fj8f7r9cRzEd4QMBTPRWxDIM14ZN47NfAWsJgL34Bx4at4Lvwdngvd9b8KqgbjQpGbMXzzgRGovytVFTBEzIXU47kQCd4U"+
  191. "ofJPvHl8JwyTjRS55hbKoor3UJLDE1i/PcPKCBAIDATjQlKiK67XjVYdcnkZgD2txroiAUb8W9dtn57DvTsbM+3wIsdocXDEN7TdPKgaSl+tU1"+
  192. "xq9oqiB5yMaZCPho8uUEbFU9U6u3N7lEMLTJGeA0RfX+5FMRrpXPFrbrlJ8uNUCE2H247P28Ckyfqlsy32yeKg/HTbH5JpqUDNw2B32+SaiRw7"+
  193. "ofRMePUpaAoK7KYgmd5ZIc0rLLYjJBfOWCb28xlrGhbpJvdToFdqt5PXVjEz5YOJ6g7W0fskuKW9/iZP0yLEVpR9XkkHmb6tfpcE8YwCdWNCan"+
  194. "LvAsco25JdF1j2/FLAMVU79HdOex07main90dy40511OZtTGZ+TdVd3lKZ7D3clEg9hLESHwSNnZ6239X4yLM4xYSElQ/hqSbwdmiozYG9PhF2"+
  195. "Zf0XaZnxzTK0Iot+rJ3kYoxWTLE8DR9leV62Ywbtlg4mapYOxb3lT7fQ1x4EQ44flh2oFWSPLR8LMbsc6jzJsV6OZ3TrODjHEdw9W+8OD32vd8"+
  196. "XQ6iCaIHcrSOn6qS0TKLr786234eeSAhvAQbEsVn7vrvc/487Be/O2e/+5Y5zRq2zAtz6pfcNyraJNDqMW1inNkgJ3t3VESbZ3pNzyl3KHILs0"+
  197. "51dY6msDYSlWhw40TglXxj9rw95O6gFWIuN012W/vhS50jpKXcao4gc1aLaXtJXxirbRkpZ/0e7a0pD6TDa7+GxEdEEML3VGo9udD5YUKhU3y7"+
  198. "SzWAgN6WIEIglq7LilvCjqIVLIfg8CvVGL9f5iSsCDf5hef4vMxbyvcjINuy06gZu+iPYOWNxjfrwKGYzoqqotK2aywgYVrPMh0JovfkDuN95n"+
  199. "MdVlYHbN1Mnn4TxAwuv+u3AkBlDZvRUUCwoDMUGxeMNPhTaAgWl60xhhBgCBaEMgAACReMAav7n3x598IDYJ9GxGXRAwaPOT/kfO/1AgPqLQkp"+
  200. "MiIVaHthnUS4v2y32e2BjdMPyIImUTBW3cV3R5tjVQm0MOm+D2C5+bBW9vHLjLR4lun4toQiY3Ls/v4bES/OJ4EmpZk5xhL9i5ClofYZNEsxFn"+
  201. "An/q821Tg+Cq9Er4XYGQe8ogjjLJ2b7dUsJ3auFQFNUJF7Ke7yUL2EeYYxl6vz5l4q5u8704mRbFts1E1eWMp6WIy91GPrsVlRGvtuNERfrjfE"+
  202. "YtzUI3Flcv65zJUbUBEzUnTS0fEYso2XyToAl8kb251mUY2o2lJzv5dp/1htmcjeeP2MjxC+3S45ljx7jd52Pv9XAat+ryiauFOF7YgztkoWWD"+
  203. "h62tplPH1bzDV+d0NLdaE5AfVJ09HuUYTFS+iggtvT5Euyk+unj4N2XvzW91n+GNjtgWfKOHmkinUPvYRh70Jv+wlPJrVaT8mL7GxJLqDC9jbv"+
  204. "Gznoiae6es+wQejnk3XjU366MrK/zXxngBYj9J6NnXc9mMiTFLX8WqQ8iTelTAFs2NJzPoDzrBUz4JFIEOa6Dja6dULc68g1jFDTeEHZyra7RZ"+
  205. "2ElqGDEqcNRo3SNX6feMy9EF1GOyZK0Sa87KwjKw8aM68dpsIYjfLcTXaZ6atg0BKfMnl6axeUGEaIFSP7rzj9wjzumRbG3jgUVp2lX5AK/tsO"+
  206. "7R4TQX/9/H6RiN34c9KldmPZZGANXzzTajZS9mR2OSvlJ+F4AgSko4htrMAKFTBu51/5SWNsO1vlRaaG48ZRJ+8PzuHQMdvS36gNpRPi7jhF1S"+
  207. "H3B2ycI4y0VURv6SrqJNUY/X645ZFJQ+eBO+ptG7o8axf1dcqh2beiQk+GRTeZ37LVeUlaeo9vl1/+8tyBfyT2v5lFC5E19WdKIyCuZe7r99Px"+
  208. "D/Od4Qj0TA92+DQnbCQTCMy/wwse9O4gsEebkkpPIP5GBV3Q0YBsj75XE0uSFQ1tCZSW8bNa9MUJZ/nPBfExohHlgGAAA=";
  209. Calendar cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
  210. cal.clear();
  211. cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
  212. cal.set(2017, Calendar.JULY, 1);
  213. SignatureConfig signatureConfig = prepareConfig("test", "CN=Test", pfxInput);
  214. signatureConfig.setExecutionTime(cal.getTime());
  215. SignatureInfo si = new SignatureInfo();
  216. si.setSignatureConfig(signatureConfig);
  217. XSSFWorkbook wb1 = new XSSFWorkbook();
  218. wb1.createSheet().createRow(1).createCell(1).setCellValue("Test");
  219. ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
  220. wb1.write(bos);
  221. wb1.close();
  222. OPCPackage pkg1 = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()));
  223. signatureConfig.setOpcPackage(pkg1);
  224. si.confirmSignature();
  225. assertTrue(si.verifySignature());
  226. bos.reset();
  227. pkg1.save(bos);
  228. pkg1.close();
  229. XSSFWorkbook wb2 = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()));
  230. assertEquals("Test", wb2.getSheetAt(0).getRow(1).getCell(1).getStringCellValue());
  231. OPCPackage pkg2 = wb2.getPackage();
  232. signatureConfig.setOpcPackage(pkg2);
  233. assertTrue(si.verifySignature());
  234. // xmlbeans adds line-breaks depending on the system setting, so we get different
  235. // test results on Unix/Mac/Windows
  236. // if the xml documents eventually change, this test needs to be run with the
  237. // separator set to the various system configurations
  238. String sep = SystemProperties.getProperty( "line.separator" );
  239. String signExp;
  240. assumeTrue("Hashes only known for Windows/Unix/Mac", sep == null || "\n".equals(sep) || "\r\n".equals(sep) || "\r".equals(sep));
  241. if (sep == null || "\n".equals(sep)) {
  242. // Unix
  243. signExp =
  244. "QkqTFQZjXagjRAoOWKpAGa8AR0rKqkSfBtfSWqtjBmTgyjarn+t2POHkpySIpheHAbg+90GKSH88ACMtPHbG7q"+
  245. "FL4gtgAD9Kjew6j16j0IRBwy145UlPrSLFMfF7YF7UlU1k1LBkIlRJ6Fv4MAJl6XspuzZOZIUmHZrWrdxycUQ=";
  246. } else if ("\r\n".equals(sep)){
  247. // Windows
  248. signExp =
  249. "GmAlL7+bT1r3FsMHJOp3pKg8betblYieZTjhMIrPZPRBbSzjO7KsYRGNtr0aOE3qr8xzyYJN6/8QdF5X7pUEUc"+
  250. "2m8ctrm7s5o2vZTkAqk9ENJGDjBPXX7TnuVOiVeL1cJdtjHC2QpjtRwkFR+B54G6b1OXLOFuQpP3vqR3+/XXE=";
  251. } else {
  252. // Mac
  253. signExp =
  254. "NZedY/LNTYU4nAUEUhIOg5+fKdgVtzRXKmdD3v+47E7Mb84oeiUGv9cCEE91DU3StF/JFIhjOJqavOzKnCsNcz"+
  255. "NJ4j/inggUl1OJUsicqIGQnA7E8vzWnN1kf5lINgJLv+0PyrrX9sQZbItzxUpgqyOFYcD0trid+31nRt4wtaA=";
  256. }
  257. String signAct = si.getSignatureParts().iterator().next().
  258. getSignatureDocument().getSignature().getSignatureValue().getStringValue();
  259. assertEquals(signExp, signAct);
  260. pkg2.close();
  261. wb2.close();
  262. }
  263. @Test
  264. public void office2007prettyPrintedRels() throws Exception {
  265. try (OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ)) {
  266. SignatureConfig sic = new SignatureConfig();
  267. sic.setOpcPackage(pkg);
  268. SignatureInfo si = new SignatureInfo();
  269. si.setSignatureConfig(sic);
  270. boolean isValid = si.verifySignature();
  271. assertTrue(isValid);
  272. }
  273. }
  274. @Test
  275. public void getSignerUnsigned() throws Exception {
  276. String testFiles[] = {
  277. "hello-world-unsigned.docx",
  278. "hello-world-unsigned.pptx",
  279. "hello-world-unsigned.xlsx",
  280. "hello-world-office-2010-technical-preview-unsigned.docx"
  281. };
  282. for (String testFile : testFiles) {
  283. OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ);
  284. SignatureConfig sic = new SignatureConfig();
  285. sic.setOpcPackage(pkg);
  286. SignatureInfo si = new SignatureInfo();
  287. si.setSignatureConfig(sic);
  288. List<X509Certificate> result = new ArrayList<>();
  289. for (SignaturePart sp : si.getSignatureParts()) {
  290. if (sp.validate()) {
  291. result.add(sp.getSigner());
  292. }
  293. }
  294. pkg.revert();
  295. pkg.close();
  296. assertNotNull(result);
  297. assertTrue(result.isEmpty());
  298. }
  299. }
  300. @Test
  301. public void getSigner() throws Exception {
  302. String testFiles[] = {
  303. "hyperlink-example-signed.docx",
  304. "hello-world-signed.docx",
  305. "hello-world-signed.pptx",
  306. "hello-world-signed.xlsx",
  307. "hello-world-office-2010-technical-preview.docx",
  308. "ms-office-2010-signed.docx",
  309. "ms-office-2010-signed.pptx",
  310. "ms-office-2010-signed.xlsx",
  311. "Office2010-SP1-XAdES-X-L.docx",
  312. "signed.docx",
  313. };
  314. for (String testFile : testFiles) {
  315. try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
  316. SignatureConfig sic = new SignatureConfig();
  317. sic.setOpcPackage(pkg);
  318. SignatureInfo si = new SignatureInfo();
  319. si.setSignatureConfig(sic);
  320. List<X509Certificate> result = new ArrayList<>();
  321. for (SignaturePart sp : si.getSignatureParts()) {
  322. if (sp.validate()) {
  323. result.add(sp.getSigner());
  324. }
  325. }
  326. assertNotNull(result);
  327. assertEquals("test-file: " + testFile, 1, result.size());
  328. X509Certificate signer = result.get(0);
  329. LOG.log(POILogger.DEBUG, "signer: " + signer.getSubjectX500Principal());
  330. boolean b = si.verifySignature();
  331. assertTrue("test-file: " + testFile, b);
  332. pkg.revert();
  333. }
  334. }
  335. }
  336. @Test
  337. public void getMultiSigners() throws Exception {
  338. String testFile = "hello-world-signed-twice.docx";
  339. try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
  340. SignatureConfig sic = new SignatureConfig();
  341. sic.setOpcPackage(pkg);
  342. SignatureInfo si = new SignatureInfo();
  343. si.setSignatureConfig(sic);
  344. List<X509Certificate> result = new ArrayList<>();
  345. for (SignaturePart sp : si.getSignatureParts()) {
  346. if (sp.validate()) {
  347. result.add(sp.getSigner());
  348. }
  349. }
  350. assertNotNull(result);
  351. assertEquals("test-file: " + testFile, 2, result.size());
  352. X509Certificate signer1 = result.get(0);
  353. X509Certificate signer2 = result.get(1);
  354. LOG.log(POILogger.DEBUG, "signer 1: " + signer1.getSubjectX500Principal());
  355. LOG.log(POILogger.DEBUG, "signer 2: " + signer2.getSubjectX500Principal());
  356. boolean b = si.verifySignature();
  357. assertTrue("test-file: " + testFile, b);
  358. pkg.revert();
  359. }
  360. }
  361. @Test
  362. public void testSignSpreadsheet() throws Exception {
  363. String testFile = "hello-world-unsigned.xlsx";
  364. OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
  365. sign(pkg, "Test", "CN=Test", 1);
  366. pkg.close();
  367. }
  368. @Test
  369. public void testManipulation() throws Exception {
  370. // sign & validate
  371. String testFile = "hello-world-unsigned.xlsx";
  372. @SuppressWarnings("resource")
  373. OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
  374. sign(pkg, "Test", "CN=Test", 1);
  375. // manipulate
  376. XSSFWorkbook wb = new XSSFWorkbook(pkg);
  377. wb.setSheetName(0, "manipulated");
  378. // ... I don't know, why commit is protected ...
  379. POITestCase.callMethod(XSSFWorkbook.class, wb, Void.class, "commit", new Class[0], new Object[0]);
  380. // todo: test a manipulation on a package part, which is not signed
  381. // ... maybe in combination with #56164
  382. // validate
  383. SignatureConfig sic = new SignatureConfig();
  384. sic.setOpcPackage(pkg);
  385. SignatureInfo si = new SignatureInfo();
  386. si.setSignatureConfig(sic);
  387. boolean b = si.verifySignature();
  388. assertFalse("signature should be broken", b);
  389. wb.close();
  390. }
  391. @Test
  392. public void testSignSpreadsheetWithSignatureInfo() throws Exception {
  393. initKeyPair("Test", "CN=Test");
  394. String testFile = "hello-world-unsigned.xlsx";
  395. OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
  396. SignatureConfig sic = new SignatureConfig();
  397. sic.setOpcPackage(pkg);
  398. sic.setKey(keyPair.getPrivate());
  399. sic.setSigningCertificateChain(Collections.singletonList(x509));
  400. SignatureInfo si = new SignatureInfo();
  401. si.setSignatureConfig(sic);
  402. // hash > sha1 doesn't work in excel viewer ...
  403. si.confirmSignature();
  404. List<X509Certificate> result = new ArrayList<>();
  405. for (SignaturePart sp : si.getSignatureParts()) {
  406. if (sp.validate()) {
  407. result.add(sp.getSigner());
  408. }
  409. }
  410. assertEquals(1, result.size());
  411. pkg.close();
  412. }
  413. @Test
  414. public void testSignEnvelopingDocument() throws Exception {
  415. String testFile = "hello-world-unsigned.xlsx";
  416. File sigCopy = testdata.getFile(testFile);
  417. ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
  418. final String execTimestr;
  419. try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {
  420. initKeyPair("Test", "CN=Test");
  421. final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
  422. // setup
  423. SignatureConfig signatureConfig = new SignatureConfig();
  424. signatureConfig.setOpcPackage(pkg);
  425. signatureConfig.setKey(keyPair.getPrivate());
  426. /*
  427. * We need at least 2 certificates for the XAdES-C complete certificate
  428. * refs construction.
  429. */
  430. List<X509Certificate> certificateChain = new ArrayList<>();
  431. certificateChain.add(x509);
  432. certificateChain.add(x509);
  433. signatureConfig.setSigningCertificateChain(certificateChain);
  434. signatureConfig.addSignatureFacet(new OOXMLSignatureFacet());
  435. signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet());
  436. signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet());
  437. signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
  438. signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());
  439. // check for internet, no error means it works
  440. boolean mockTsp = (getAccessError("http://timestamp.comodoca.com/rfc3161", true, 10000) != null);
  441. // http://timestamping.edelweb.fr/service/tsp
  442. // http://tsa.belgium.be/connect
  443. // http://timestamp.comodoca.com/authenticode
  444. // http://timestamp.comodoca.com/rfc3161
  445. // http://services.globaltrustfinder.com/adss/tsa
  446. signatureConfig.setTspUrl("http://timestamp.comodoca.com/rfc3161");
  447. signatureConfig.setTspRequestPolicy(null); // comodoca request fails, if default policy is set ...
  448. signatureConfig.setTspOldProtocol(false);
  449. signatureConfig.setXadesDigestAlgo(HashAlgorithm.sha512);
  450. signatureConfig.setXadesRole("Xades Reviewer");
  451. signatureConfig.setSignatureDescription("test xades signature");
  452. execTimestr = signatureConfig.formatExecutionTime();
  453. //set proxy info if any
  454. String proxy = System.getProperty("http_proxy");
  455. if (proxy != null && proxy.trim().length() > 0) {
  456. signatureConfig.setProxyUrl(proxy);
  457. }
  458. if (mockTsp) {
  459. TimeStampService tspService = new TimeStampService() {
  460. @Override
  461. public byte[] timeStamp(byte[] data, RevocationData revocationData) {
  462. revocationData.addCRL(crl);
  463. return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
  464. }
  465. @Override
  466. public void setSignatureConfig(SignatureConfig config) {
  467. // empty on purpose
  468. }
  469. };
  470. signatureConfig.setTspService(tspService);
  471. } else {
  472. TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
  473. for (X509Certificate certificate : validateChain) {
  474. LOG.log(POILogger.DEBUG, "certificate: " + certificate.getSubjectX500Principal());
  475. LOG.log(POILogger.DEBUG, "validity: " + certificate.getNotBefore() + " - " + certificate.getNotAfter());
  476. }
  477. };
  478. signatureConfig.setTspValidator(tspValidator);
  479. signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb"));
  480. }
  481. final RevocationData revocationData = new RevocationData();
  482. revocationData.addCRL(crl);
  483. OCSPResp ocspResp = createOcspResp(x509, false,
  484. x509, x509, keyPair.getPrivate(), "SHA1withRSA", cal.getTimeInMillis());
  485. revocationData.addOCSP(ocspResp.getEncoded());
  486. RevocationDataService revocationDataService = revocationChain -> revocationData;
  487. signatureConfig.setRevocationDataService(revocationDataService);
  488. // operate
  489. SignatureInfo si = new SignatureInfo();
  490. si.setSignatureConfig(signatureConfig);
  491. try {
  492. si.confirmSignature();
  493. } catch (RuntimeException e) {
  494. pkg.close();
  495. // only allow a ConnectException because of timeout, we see this in Jenkins from time to time...
  496. if (e.getCause() == null) {
  497. throw e;
  498. }
  499. if ((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException)) {
  500. Assume.assumeFalse("Only allowing ConnectException with 'timed out' as message here, but had: " + e,
  501. e.getCause().getMessage().contains("timed out"));
  502. } else if (e.getCause() instanceof IOException) {
  503. Assume.assumeFalse("Only allowing IOException with 'Error contacting TSP server' as message here, but had: " + e,
  504. e.getCause().getMessage().contains("Error contacting TSP server"));
  505. } else if (e.getCause() instanceof RuntimeException) {
  506. Assume.assumeFalse("Only allowing RuntimeException with 'This site is cur' as message here, but had: " + e,
  507. e.getCause().getMessage().contains("This site is cur"));
  508. }
  509. throw e;
  510. }
  511. // verify
  512. Iterator<SignaturePart> spIter = si.getSignatureParts().iterator();
  513. assertTrue("Had: " + si.getSignatureConfig().getOpcPackage().
  514. getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN),
  515. spIter.hasNext());
  516. SignaturePart sp = spIter.next();
  517. boolean valid = sp.validate();
  518. assertTrue(valid);
  519. SignatureDocument sigDoc = sp.getSignatureDocument();
  520. String declareNS =
  521. "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
  522. + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; ";
  523. String digestValXQuery = declareNS +
  524. "$this/ds:Signature/ds:SignedInfo/ds:Reference";
  525. for (ReferenceType rt : (ReferenceType[]) sigDoc.selectPath(digestValXQuery)) {
  526. assertNotNull(rt.getDigestValue());
  527. assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());
  528. }
  529. String certDigestXQuery = declareNS +
  530. "$this//xades:SigningCertificate/xades:Cert/xades:CertDigest";
  531. XmlObject xoList[] = sigDoc.selectPath(certDigestXQuery);
  532. assertEquals(xoList.length, 1);
  533. DigestAlgAndValueType certDigest = (DigestAlgAndValueType) xoList[0];
  534. assertNotNull(certDigest.getDigestValue());
  535. String qualPropXQuery = declareNS +
  536. "$this/ds:Signature/ds:Object/xades:QualifyingProperties";
  537. xoList = sigDoc.selectPath(qualPropXQuery);
  538. assertEquals(xoList.length, 1);
  539. QualifyingPropertiesType qualProp = (QualifyingPropertiesType) xoList[0];
  540. boolean qualPropXsdOk = qualProp.validate();
  541. assertTrue(qualPropXsdOk);
  542. pkg.save(bos);
  543. }
  544. try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
  545. SignatureConfig signatureConfig = new SignatureConfig();
  546. signatureConfig.setOpcPackage(pkg);
  547. signatureConfig.setUpdateConfigOnValidate(true);
  548. SignatureInfo si = new SignatureInfo();
  549. si.setSignatureConfig(signatureConfig);
  550. assertTrue(si.verifySignature());
  551. assertEquals(HashAlgorithm.sha512, signatureConfig.getXadesDigestAlgo());
  552. assertEquals("Xades Reviewer", signatureConfig.getXadesRole());
  553. assertEquals("test xades signature", signatureConfig.getSignatureDescription());
  554. assertEquals(execTimestr, signatureConfig.formatExecutionTime());
  555. }
  556. }
  557. public static String getAccessError(String destinationUrl, boolean fireRequest, int timeout) {
  558. URL url;
  559. try {
  560. url = new URL(destinationUrl);
  561. } catch (MalformedURLException e) {
  562. throw new IllegalArgumentException("Invalid destination URL", e);
  563. }
  564. HttpURLConnection conn = null;
  565. try {
  566. conn = (HttpURLConnection) url.openConnection();
  567. // set specified timeout if non-zero
  568. if(timeout != 0) {
  569. conn.setConnectTimeout(timeout);
  570. conn.setReadTimeout(timeout);
  571. }
  572. conn.setDoOutput(false);
  573. conn.setDoInput(true);
  574. /* if connecting is not possible this will throw a connection refused exception */
  575. conn.connect();
  576. if (fireRequest) {
  577. InputStream is = null;
  578. try {
  579. is = conn.getInputStream();
  580. } finally {
  581. IOUtils.closeQuietly(is);
  582. }
  583. }
  584. /* if connecting is possible we return true here */
  585. return null;
  586. } catch (IOException e) {
  587. /* exception is thrown -> server not available */
  588. return e.getClass().getName() + ": " + e.getMessage();
  589. } finally {
  590. if (conn != null) {
  591. conn.disconnect();
  592. }
  593. }
  594. }
  595. @Test
  596. public void testCertChain() throws Exception {
  597. KeyStore keystore = KeyStore.getInstance("PKCS12");
  598. String password = "test";
  599. InputStream is = testdata.openResourceAsStream("chaintest.pfx");
  600. keystore.load(is, password.toCharArray());
  601. is.close();
  602. Key key = keystore.getKey("poitest", password.toCharArray());
  603. Certificate chainList[] = keystore.getCertificateChain("poitest");
  604. List<X509Certificate> certChain = new ArrayList<>();
  605. for (Certificate c : chainList) {
  606. certChain.add((X509Certificate)c);
  607. }
  608. x509 = certChain.get(0);
  609. keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
  610. String testFile = "hello-world-unsigned.xlsx";
  611. OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
  612. SignatureConfig signatureConfig = new SignatureConfig();
  613. signatureConfig.setKey(keyPair.getPrivate());
  614. signatureConfig.setSigningCertificateChain(certChain);
  615. Calendar oldCal = LocaleUtil.getLocaleCalendar(2007, 7, 1);
  616. signatureConfig.setExecutionTime(oldCal.getTime());
  617. signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
  618. signatureConfig.setOpcPackage(pkg);
  619. SignatureInfo si = new SignatureInfo();
  620. si.setSignatureConfig(signatureConfig);
  621. si.confirmSignature();
  622. for (SignaturePart sp : si.getSignatureParts()){
  623. assertTrue("Could not validate", sp.validate());
  624. X509Certificate signer = sp.getSigner();
  625. assertNotNull("signer undefined?!", signer);
  626. List<X509Certificate> certChainRes = sp.getCertChain();
  627. assertEquals(3, certChainRes.size());
  628. }
  629. pkg.close();
  630. }
  631. @Test
  632. public void testNonSha1() throws Exception {
  633. String testFile = "hello-world-unsigned.xlsx";
  634. initKeyPair("Test", "CN=Test");
  635. SignatureConfig signatureConfig = new SignatureConfig();
  636. signatureConfig.setKey(keyPair.getPrivate());
  637. signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
  638. HashAlgorithm testAlgo[] = { HashAlgorithm.sha224, HashAlgorithm.sha256
  639. , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 };
  640. for (HashAlgorithm ha : testAlgo) {
  641. OPCPackage pkg = null;
  642. try {
  643. signatureConfig.setDigestAlgo(ha);
  644. pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
  645. signatureConfig.setOpcPackage(pkg);
  646. SignatureInfo si = new SignatureInfo();
  647. si.setSignatureConfig(signatureConfig);
  648. si.confirmSignature();
  649. boolean b = si.verifySignature();
  650. assertTrue("Signature not correctly calculated for " + ha, b);
  651. } catch (EncryptedDocumentException e) {
  652. Assume.assumeTrue(e.getMessage().startsWith("Export Restrictions"));
  653. } finally {
  654. if (pkg != null) {
  655. pkg.close();
  656. }
  657. }
  658. }
  659. }
  660. @Test
  661. public void bug58630() throws Exception {
  662. // test deletion of sheet 0 and signing
  663. File tpl = copy(testdata.getFile("bug58630.xlsx"));
  664. SXSSFWorkbook wb1 = new SXSSFWorkbook((XSSFWorkbook)WorkbookFactory.create(tpl), 10);
  665. wb1.setCompressTempFiles(true);
  666. wb1.removeSheetAt(0);
  667. ByteArrayOutputStream os = new ByteArrayOutputStream();
  668. wb1.write(os);
  669. wb1.close();
  670. OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(os.toByteArray()));
  671. initKeyPair("Test", "CN=Test");
  672. SignatureConfig signatureConfig = new SignatureConfig();
  673. signatureConfig.setKey(keyPair.getPrivate());
  674. signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
  675. signatureConfig.setOpcPackage(pkg);
  676. SignatureInfo si = new SignatureInfo();
  677. si.setSignatureConfig(signatureConfig);
  678. si.confirmSignature();
  679. assertTrue("invalid signature", si.verifySignature());
  680. pkg.close();
  681. }
  682. @Test
  683. public void testMultiSign() throws Exception {
  684. cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
  685. cal.clear();
  686. cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
  687. cal.set(2018, Calendar.DECEMBER, 14);
  688. // test signing with separate opened packages
  689. File tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
  690. try (OPCPackage pkg = OPCPackage.open(tpl)) {
  691. signPkg63011(pkg, "bug63011_key1.pem", true);
  692. }
  693. try (OPCPackage pkg = OPCPackage.open(tpl)) {
  694. signPkg63011(pkg, "bug63011_key2.pem", true);
  695. }
  696. verifyPkg63011(tpl, true);
  697. // test signing with single opened package
  698. tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
  699. try (OPCPackage pkg = OPCPackage.open(tpl)) {
  700. signPkg63011(pkg, "bug63011_key1.pem", true);
  701. signPkg63011(pkg, "bug63011_key2.pem", true);
  702. }
  703. verifyPkg63011(tpl, true);
  704. try (OPCPackage pkg = OPCPackage.open(tpl)) {
  705. signPkg63011(pkg, "bug63011_key1.pem", true);
  706. signPkg63011(pkg, "bug63011_key2.pem", false);
  707. }
  708. verifyPkg63011(tpl, false);
  709. }
  710. private void verifyPkg63011(File tpl, boolean multi) throws InvalidFormatException, IOException {
  711. try (OPCPackage pkg = OPCPackage.open(tpl, PackageAccess.READ)) {
  712. SignatureConfig sic = new SignatureConfig();
  713. sic.setOpcPackage(pkg);
  714. SignatureInfo si = new SignatureInfo();
  715. si.setSignatureConfig(sic);
  716. List<X509Certificate> result = new ArrayList<>();
  717. for (SignaturePart sp : si.getSignatureParts()) {
  718. if (sp.validate()) {
  719. result.add(sp.getSigner());
  720. }
  721. }
  722. assertNotNull(result);
  723. if (multi) {
  724. assertEquals(2, result.size());
  725. assertEquals("CN=Muj Klic", result.get(0).getSubjectDN().toString());
  726. assertEquals("CN=My Second key", result.get(1).getSubjectDN().toString());
  727. } else {
  728. assertEquals(1, result.size());
  729. assertEquals("CN=My Second key", result.get(0).getSubjectDN().toString());
  730. }
  731. assertTrue(si.verifySignature());
  732. pkg.revert();
  733. }
  734. }
  735. private void signPkg63011(OPCPackage pkg, String pemFile, boolean multi)
  736. throws IOException, CertificateException, XMLSignatureException, MarshalException {
  737. assertNotNull(pkg);
  738. initKeyFromPEM(testdata.getFile(pemFile));
  739. SignatureConfig config = new SignatureConfig();
  740. config.setKey(keyPair.getPrivate());
  741. config.setSigningCertificateChain(Collections.singletonList(x509));
  742. config.setExecutionTime(cal.getTime());
  743. config.setAllowMultipleSignatures(multi);
  744. config.setOpcPackage(pkg);
  745. SignatureInfo si = new SignatureInfo();
  746. si.setSignatureConfig(config);
  747. si.confirmSignature();
  748. }
  749. @Test
  750. public void testRetrieveCertificate() throws InvalidFormatException, IOException {
  751. SignatureConfig sic = new SignatureConfig();
  752. final File file = testdata.getFile("PPT2016withComment.pptx");
  753. try (final OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ)) {
  754. sic.setOpcPackage(pkg);
  755. sic.setUpdateConfigOnValidate(true);
  756. SignatureInfo si = new SignatureInfo();
  757. si.setSignatureConfig(sic);
  758. assertTrue(si.verifySignature());
  759. }
  760. final List<X509Certificate> certs = sic.getSigningCertificateChain();
  761. assertEquals(1, certs.size());
  762. assertEquals("CN=Test", certs.get(0).getSubjectDN().getName());
  763. assertEquals("SuperDuper-Reviewer", sic.getXadesRole());
  764. assertEquals("Purpose for signing", sic.getSignatureDescription());
  765. assertEquals("2018-06-10T09:00:54Z", sic.formatExecutionTime());
  766. assertEquals(CanonicalizationMethod.INCLUSIVE, sic.getCanonicalizationMethod());
  767. }
  768. private SignatureConfig prepareConfig(String alias, String signerDn, String pfxInput) throws Exception {
  769. initKeyPair(alias, signerDn, pfxInput);
  770. SignatureConfig signatureConfig = new SignatureConfig();
  771. signatureConfig.setKey(keyPair.getPrivate());
  772. signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
  773. signatureConfig.setExecutionTime(cal.getTime());
  774. signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
  775. return signatureConfig;
  776. }
  777. private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {
  778. SignatureConfig signatureConfig = prepareConfig(alias, signerDn, null);
  779. signatureConfig.setOpcPackage(pkgCopy);
  780. SignatureInfo si = new SignatureInfo();
  781. si.setSignatureConfig(signatureConfig);
  782. final Document document = DocumentHelper.createDocument();
  783. final DOMSignContext xmlSignContext = si.createXMLSignContext(document);
  784. // operate
  785. final DOMSignedInfo signedInfo = si.preSign(xmlSignContext);
  786. // verify
  787. assertNotNull(signedInfo);
  788. assertEquals("Office OpenXML Document", signatureConfig.getSignatureDescription());
  789. // setup: key material, signature value
  790. final String signatureValue = si.signDigest(xmlSignContext, signedInfo);
  791. // operate: postSign
  792. si.postSign(xmlSignContext, signatureValue);
  793. // verify: signature
  794. si.getSignatureConfig().setOpcPackage(pkgCopy);
  795. List<X509Certificate> result = new ArrayList<>();
  796. for (SignaturePart sp : si.getSignatureParts()) {
  797. if (sp.validate()) {
  798. result.add(sp.getSigner());
  799. }
  800. }
  801. assertEquals(signerCount, result.size());
  802. }
  803. private void initKeyPair(String alias, String subjectDN) throws Exception {
  804. initKeyPair(alias, subjectDN, null);
  805. }
  806. private void initKeyPair(String alias, String subjectDN, String pfxInput) throws Exception {
  807. final char password[] = "test".toCharArray();
  808. File file = new File("build/test.pfx");
  809. KeyStore keystore = KeyStore.getInstance("PKCS12");
  810. if (pfxInput != null) {
  811. InputStream fis = new ByteArrayInputStream(RawDataUtil.decompress(pfxInput));
  812. keystore.load(fis, password);
  813. fis.close();
  814. } else if (file.exists()) {
  815. InputStream fis = new FileInputStream(file);
  816. keystore.load(fis, password);
  817. fis.close();
  818. } else {
  819. keystore.load(null, password);
  820. }
  821. if (keystore.isKeyEntry(alias)) {
  822. Key key = keystore.getKey(alias, password);
  823. x509 = (X509Certificate)keystore.getCertificate(alias);
  824. keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
  825. } else {
  826. keyPair = generateKeyPair();
  827. Date notBefore = cal.getTime();
  828. Calendar cal2 = (Calendar)cal.clone();
  829. cal2.add(Calendar.YEAR, 1);
  830. Date notAfter = cal2.getTime();
  831. KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature);
  832. x509 = generateCertificate(keyPair.getPublic(), subjectDN
  833. , notBefore, notAfter, null, keyPair.getPrivate(), true, 0, null, null, keyUsage);
  834. keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
  835. if (pfxInput == null) {
  836. FileOutputStream fos = new FileOutputStream(file);
  837. keystore.store(fos, password);
  838. fos.close();
  839. }
  840. }
  841. }
  842. private void initKeyFromPEM(File pemFile) throws IOException, CertificateException {
  843. // see https://stackoverflow.com/questions/11787571/how-to-read-pem-file-to-get-private-and-public-key
  844. PrivateKey key = null;
  845. x509 = null;
  846. try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(pemFile), StandardCharsets.ISO_8859_1))) {
  847. PEMParser parser = new PEMParser(br);
  848. for (Object obj; (obj = parser.readObject()) != null; ) {
  849. if (obj instanceof PrivateKeyInfo) {
  850. key = new JcaPEMKeyConverter().setProvider("BC").getPrivateKey((PrivateKeyInfo)obj);
  851. } else if (obj instanceof X509CertificateHolder) {
  852. x509 = new JcaX509CertificateConverter().setProvider("BC").getCertificate((X509CertificateHolder)obj);
  853. }
  854. }
  855. }
  856. if (key != null && x509 != null) {
  857. keyPair = new KeyPair(x509.getPublicKey(), key);
  858. }
  859. }
  860. private static File copy(File input) throws IOException {
  861. String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1");
  862. if (extension == null || extension.isEmpty()) {
  863. extension = ".zip";
  864. }
  865. // ensure that we create the "build" directory as it might not be existing
  866. // in the Sonar Maven runs where we are at a different source directory
  867. File buildDir = new File("build");
  868. if(!buildDir.exists()) {
  869. assertTrue("Failed to create " + buildDir.getAbsolutePath(), buildDir.mkdirs());
  870. }
  871. File tmpFile = new File(buildDir, "sigtest"+extension);
  872. try (OutputStream fos = new FileOutputStream(tmpFile)) {
  873. try (InputStream fis = new FileInputStream(input)) {
  874. IOUtils.copy(fis, fos);
  875. }
  876. }
  877. return tmpFile;
  878. }
  879. private static KeyPair generateKeyPair() throws Exception {
  880. KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  881. SecureRandom random = new SecureRandom();
  882. keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024,
  883. RSAKeyGenParameterSpec.F4), random);
  884. return keyPairGenerator.generateKeyPair();
  885. }
  886. private static X509Certificate generateCertificate(PublicKey subjectPublicKey,
  887. String subjectDn, Date notBefore, Date notAfter,
  888. X509Certificate issuerCertificate, PrivateKey issuerPrivateKey,
  889. boolean caFlag, int pathLength, String crlUri, String ocspUri,
  890. KeyUsage keyUsage)
  891. throws IOException, OperatorCreationException, CertificateException
  892. {
  893. String signatureAlgorithm = "SHA1withRSA";
  894. X500Name issuerName;
  895. if (issuerCertificate != null) {
  896. issuerName = new X509CertificateHolder(issuerCertificate.getEncoded()).getIssuer();
  897. } else {
  898. issuerName = new X500Name(subjectDn);
  899. }
  900. RSAPublicKey rsaPubKey = (RSAPublicKey)subjectPublicKey;
  901. RSAKeyParameters rsaSpec = new RSAKeyParameters(false, rsaPubKey.getModulus(), rsaPubKey.getPublicExponent());
  902. SubjectPublicKeyInfo subjectPublicKeyInfo =
  903. SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaSpec);
  904. DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
  905. .setProvider("BC").build().get(CertificateID.HASH_SHA1);
  906. X509v3CertificateBuilder certificateGenerator = new X509v3CertificateBuilder(
  907. issuerName
  908. , new BigInteger(128, new SecureRandom())
  909. , notBefore
  910. , notAfter
  911. , new X500Name(subjectDn)
  912. , subjectPublicKeyInfo
  913. );
  914. X509ExtensionUtils exUtils = new X509ExtensionUtils(digestCalc);
  915. SubjectKeyIdentifier subKeyId = exUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo);
  916. AuthorityKeyIdentifier autKeyId = (issuerCertificate != null)
  917. ? exUtils.createAuthorityKeyIdentifier(new X509CertificateHolder(issuerCertificate.getEncoded()))
  918. : exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
  919. certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
  920. certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
  921. if (caFlag) {
  922. BasicConstraints bc;
  923. if (-1 == pathLength) {
  924. bc = new BasicConstraints(true);
  925. } else {
  926. bc = new BasicConstraints(pathLength);
  927. }
  928. certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
  929. }
  930. if (null != crlUri) {
  931. int uri = GeneralName.uniformResourceIdentifier;
  932. DERIA5String crlUriDer = new DERIA5String(crlUri);
  933. GeneralName gn = new GeneralName(uri, crlUriDer);
  934. DERSequence gnDer = new DERSequence(gn);
  935. GeneralNames gns = GeneralNames.getInstance(gnDer);
  936. DistributionPointName dpn = new DistributionPointName(0, gns);
  937. DistributionPoint distp = new DistributionPoint(dpn, null, null);
  938. DERSequence distpDer = new DERSequence(distp);
  939. certificateGenerator.addExtension(Extension.cRLDistributionPoints, false, distpDer);
  940. }
  941. if (null != ocspUri) {
  942. int uri = GeneralName.uniformResourceIdentifier;
  943. GeneralName ocspName = new GeneralName(uri, ocspUri);
  944. AuthorityInformationAccess authorityInformationAccess =
  945. new AuthorityInformationAccess(X509ObjectIdentifiers.ocspAccessMethod, ocspName);
  946. certificateGenerator.addExtension(Extension.authorityInfoAccess, false, authorityInformationAccess);
  947. }
  948. if (null != keyUsage) {
  949. certificateGenerator.addExtension(Extension.keyUsage, true, keyUsage);
  950. }
  951. JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(signatureAlgorithm);
  952. signerBuilder.setProvider("BC");
  953. X509CertificateHolder certHolder =
  954. certificateGenerator.build(signerBuilder.build(issuerPrivateKey));
  955. /*
  956. * Next certificate factory trick is needed to make sure that the
  957. * certificate delivered to the caller is provided by the default
  958. * security provider instead of BouncyCastle. If we don't do this trick
  959. * we might run into trouble when trying to use the CertPath validator.
  960. */
  961. // CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
  962. // certificate = (X509Certificate) certificateFactory
  963. // .generateCertificate(new ByteArrayInputStream(certificate
  964. // .getEncoded()));
  965. return new JcaX509CertificateConverter().getCertificate(certHolder);
  966. }
  967. private static X509CRL generateCrl(X509Certificate issuer, PrivateKey issuerPrivateKey)
  968. throws CertificateEncodingException, IOException, CRLException, OperatorCreationException {
  969. X509CertificateHolder holder = new X509CertificateHolder(issuer.getEncoded());
  970. X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(holder.getIssuer(), new Date());
  971. crlBuilder.setNextUpdate(new Date(new Date().getTime() + 100000));
  972. JcaContentSignerBuilder contentBuilder = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC");
  973. CRLNumber crlNumber = new CRLNumber(new BigInteger("1234"));
  974. crlBuilder.addExtension(Extension.cRLNumber, false, crlNumber);
  975. X509CRLHolder x509Crl = crlBuilder.build(contentBuilder.build(issuerPrivateKey));
  976. return new JcaX509CRLConverter().setProvider("BC").getCRL(x509Crl);
  977. }
  978. private static OCSPResp createOcspResp(X509Certificate certificate,
  979. boolean revoked, X509Certificate issuerCertificate,
  980. X509Certificate ocspResponderCertificate,
  981. PrivateKey ocspResponderPrivateKey, String signatureAlgorithm,
  982. long nonceTimeinMillis)
  983. throws Exception {
  984. DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
  985. .setProvider("BC").build().get(CertificateID.HASH_SHA1);
  986. X509CertificateHolder issuerHolder = new X509CertificateHolder(issuerCertificate.getEncoded());
  987. CertificateID certId = new CertificateID(digestCalc, issuerHolder, certificate.getSerialNumber());
  988. // request
  989. //create a nonce to avoid replay attack
  990. BigInteger nonce = BigInteger.valueOf(nonceTimeinMillis);
  991. DEROctetString nonceDer = new DEROctetString(nonce.toByteArray());
  992. Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, nonceDer);
  993. Extensions exts = new Extensions(ext);
  994. OCSPReqBuilder ocspReqBuilder = new OCSPReqBuilder();
  995. ocspReqBuilder.addRequest(certId);
  996. ocspReqBuilder.setRequestExtensions(exts);
  997. OCSPReq ocspReq = ocspReqBuilder.build();
  998. SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo
  999. (CertificateID.HASH_SHA1, ocspResponderCertificate.getPublicKey().getEncoded());
  1000. BasicOCSPRespBuilder basicOCSPRespBuilder = new BasicOCSPRespBuilder(keyInfo, digestCalc);
  1001. basicOCSPRespBuilder.setResponseExtensions(exts);
  1002. // request processing
  1003. Req[] requestList = ocspReq.getRequestList();
  1004. for (Req ocspRequest : requestList) {
  1005. CertificateID certificateID = ocspRequest.getCertID();
  1006. CertificateStatus certificateStatus = CertificateStatus.GOOD;
  1007. if (revoked) {
  1008. certificateStatus = new RevokedStatus(new Date(), CRLReason.privilegeWithdrawn);
  1009. }
  1010. basicOCSPRespBuilder.addResponse(certificateID, certificateStatus);
  1011. }
  1012. // basic response generation
  1013. X509CertificateHolder[] chain = null;
  1014. if (!ocspResponderCertificate.equals(issuerCertificate)) {
  1015. // TODO: HorribleProxy can't convert array input params yet
  1016. chain = new X509CertificateHolder[] {
  1017. new X509CertificateHolder(ocspResponderCertificate.getEncoded()),
  1018. issuerHolder
  1019. };
  1020. }
  1021. ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA")
  1022. .setProvider("BC").build(ocspResponderPrivateKey);
  1023. BasicOCSPResp basicOCSPResp = basicOCSPRespBuilder.build(contentSigner, chain, new Date(nonceTimeinMillis));
  1024. OCSPRespBuilder ocspRespBuilder = new OCSPRespBuilder();
  1025. return ocspRespBuilder.build(OCSPRespBuilder.SUCCESSFUL, basicOCSPResp);
  1026. }
  1027. }