12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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.
- ==================================================================== */
-
- /* ====================================================================
- This product contains an ASLv2 licensed version of the OOXML signer
- package from the eID Applet project
- http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
- Copyright (C) 2008-2014 FedICT.
- ================================================================= */
- package org.apache.poi.poifs.crypt.dsig;
-
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertFalse;
- import static org.junit.jupiter.api.Assertions.assertNotNull;
- import static org.junit.jupiter.api.Assertions.assertTrue;
- import static org.junit.jupiter.api.Assumptions.assumeFalse;
- import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.math.BigInteger;
- import java.net.ConnectException;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.SocketTimeoutException;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.security.Key;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.KeyStore;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.SecureRandom;
- import java.security.cert.CRLException;
- import java.security.cert.Certificate;
- import java.security.cert.CertificateEncodingException;
- import java.security.cert.CertificateException;
- import java.security.cert.X509CRL;
- import java.security.cert.X509Certificate;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.RSAKeyGenParameterSpec;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Collections;
- import java.util.Date;
- import java.util.Iterator;
- import java.util.List;
- import java.util.function.BiFunction;
- import java.util.function.Supplier;
-
- import javax.xml.crypto.MarshalException;
- import javax.xml.crypto.dsig.CanonicalizationMethod;
- import javax.xml.crypto.dsig.XMLSignatureException;
- import javax.xml.crypto.dsig.dom.DOMSignContext;
-
- import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.poi.EncryptedDocumentException;
- import org.apache.poi.POIDataSamples;
- import org.apache.poi.POITestCase;
- import org.apache.poi.ooxml.POIXMLDocument;
- import org.apache.poi.ooxml.util.DocumentHelper;
- import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
- import org.apache.poi.openxml4j.opc.OPCPackage;
- import org.apache.poi.openxml4j.opc.PackageAccess;
- import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
- import org.apache.poi.poifs.crypt.CryptoFunctions;
- import org.apache.poi.poifs.crypt.HashAlgorithm;
- import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
- import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
- import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
- import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
- import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
- import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
- import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
- import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
- import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
- import org.apache.poi.poifs.storage.RawDataUtil;
- import org.apache.poi.ss.usermodel.WorkbookFactory;
- import org.apache.poi.util.IOUtils;
- import org.apache.poi.util.LocaleUtil;
- import org.apache.poi.util.TempFile;
- import org.apache.poi.xssf.streaming.SXSSFWorkbook;
- import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
- import org.apache.poi.xssf.usermodel.XSSFSheet;
- import org.apache.poi.xssf.usermodel.XSSFSignatureLine;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
- import org.apache.poi.xwpf.usermodel.XWPFDocument;
- import org.apache.poi.xwpf.usermodel.XWPFSignatureLine;
- import org.apache.xmlbeans.SystemProperties;
- import org.apache.xmlbeans.XmlException;
- import org.apache.xmlbeans.XmlObject;
- import org.bouncycastle.asn1.DEROctetString;
- import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
- import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
- import org.bouncycastle.asn1.x500.X500Name;
- import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
- import org.bouncycastle.asn1.x509.BasicConstraints;
- import org.bouncycastle.asn1.x509.CRLNumber;
- import org.bouncycastle.asn1.x509.Extension;
- import org.bouncycastle.asn1.x509.Extensions;
- import org.bouncycastle.asn1.x509.KeyUsage;
- import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
- import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
- import org.bouncycastle.cert.X509CRLHolder;
- import org.bouncycastle.cert.X509CertificateHolder;
- import org.bouncycastle.cert.X509ExtensionUtils;
- import org.bouncycastle.cert.X509v2CRLBuilder;
- import org.bouncycastle.cert.X509v3CertificateBuilder;
- import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
- import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
- import org.bouncycastle.cert.ocsp.BasicOCSPResp;
- import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
- import org.bouncycastle.cert.ocsp.CertificateID;
- import org.bouncycastle.cert.ocsp.CertificateStatus;
- import org.bouncycastle.cert.ocsp.OCSPReq;
- import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
- import org.bouncycastle.cert.ocsp.OCSPResp;
- import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
- import org.bouncycastle.cert.ocsp.Req;
- import org.bouncycastle.crypto.params.RSAKeyParameters;
- import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
- import org.bouncycastle.openssl.PEMParser;
- import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
- import org.bouncycastle.operator.ContentSigner;
- import org.bouncycastle.operator.DigestCalculator;
- import org.bouncycastle.operator.OperatorCreationException;
- import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
- import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
- import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
- import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
- import org.junit.jupiter.api.AfterAll;
- import org.junit.jupiter.api.BeforeAll;
- import org.junit.jupiter.api.Disabled;
- import org.junit.jupiter.api.Test;
- import org.w3.x2000.x09.xmldsig.ReferenceType;
- import org.w3.x2000.x09.xmldsig.SignatureDocument;
- import org.w3c.dom.Document;
-
- class TestSignatureInfo {
- private static final Logger LOG = LogManager.getLogger(TestSignatureInfo.class);
- private static final POIDataSamples testdata = POIDataSamples.getXmlDSignInstance();
-
- private static Calendar cal;
- private KeyPair keyPair;
- private X509Certificate x509;
-
- @BeforeAll
- public static void setUpClass() {
- POITestCase.setImageIOCacheDir();
- }
-
- @AfterAll
- public static void removeUserLocale() {
- LocaleUtil.resetUserLocale();
- }
-
- @BeforeAll
- public static void initBouncy() {
- CryptoFunctions.registerBouncyCastle();
-
- // Set cal to now ... only set to fixed date for debugging ...
- LocaleUtil.resetUserLocale();
- LocaleUtil.resetUserTimeZone();
-
- cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
- assertNotNull(cal);
-
- // don't run this test when we are using older Xerces as it triggers an XML Parser backwards compatibility issue
- // in the xmlsec jar file
- String additionalJar = System.getProperty("additionaljar");
- //System.out.println("Having: " + additionalJar);
- assumeTrue(additionalJar == null || additionalJar.trim().length() == 0,
- "Not running TestSignatureInfo because we are testing with additionaljar set to " + additionalJar);
-
- System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
-
- // Set line.separator for bug61182
- // System.setProperty("line.separator", "\n");
- }
-
- @Disabled("This test is very sensitive, it breaks with every little change to the produced XML")
- @Test
- void bug61182() throws Exception {
- final String pfxInput =
- "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";
-
- // Unix
- final String unixSignExp =
- "QkqTFQZjXagjRAoOWKpAGa8AR0rKqkSfBtfSWqtjBmTgyjarn+t2POHkpySIpheHAbg+90GKSH88ACMtPHbG7q" +
- "FL4gtgAD9Kjew6j16j0IRBwy145UlPrSLFMfF7YF7UlU1k1LBkIlRJ6Fv4MAJl6XspuzZOZIUmHZrWrdxycUQ=";
-
- // Windows
- final String winSignExp =
- "GmAlL7+bT1r3FsMHJOp3pKg8betblYieZTjhMIrPZPRBbSzjO7KsYRGNtr0aOE3qr8xzyYJN6/8QdF5X7pUEUc" +
- "2m8ctrm7s5o2vZTkAqk9ENJGDjBPXX7TnuVOiVeL1cJdtjHC2QpjtRwkFR+B54G6b1OXLOFuQpP3vqR3+/XXE=";
-
- // Mac
- final String macSignExp =
- "NZedY/LNTYU4nAUEUhIOg5+fKdgVtzRXKmdD3v+47E7Mb84oeiUGv9cCEE91DU3StF/JFIhjOJqavOzKnCsNcz" +
- "NJ4j/inggUl1OJUsicqIGQnA7E8vzWnN1kf5lINgJLv+0PyrrX9sQZbItzxUpgqyOFYcD0trid+31nRt4wtaA=";
-
-
-
- Calendar cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
- cal.clear();
- cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
- cal.set(2017, Calendar.JULY, 1);
-
- SignatureConfig signatureConfig = prepareConfig(pfxInput);
- signatureConfig.setExecutionTime(cal.getTime());
-
- SignatureInfo si = new SignatureInfo();
- si.setSignatureConfig(signatureConfig);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
- try (XSSFWorkbook wb1 = new XSSFWorkbook()) {
- wb1.createSheet().createRow(1).createCell(1).setCellValue("Test");
- wb1.write(bos);
- }
-
- try (OPCPackage pkg1 = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
- si.setOpcPackage(pkg1);
- si.confirmSignature();
- assertTrue(si.verifySignature());
- bos.reset();
- pkg1.save(bos);
- }
-
- try (XSSFWorkbook wb2 = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()))) {
- assertEquals("Test", wb2.getSheetAt(0).getRow(1).getCell(1).getStringCellValue());
- OPCPackage pkg2 = wb2.getPackage();
- si.setOpcPackage(pkg2);
- assertTrue(si.verifySignature());
-
- // xmlbeans adds line-breaks depending on the system setting, so we get different
- // test results on Unix/Mac/Windows
- // if the xml documents eventually change, this test needs to be run with the
- // separator set to the various system configurations
- String sep = SystemProperties.getProperty("line.separator");
- String signExp;
- assumeTrue(sep == null || "\n".equals(sep) || "\r\n".equals(sep) || "\r".equals(sep), "Hashes only known for Windows/Unix/Mac");
- signExp = (sep == null || "\n".equals(sep)) ? unixSignExp : ("\r\n".equals(sep)) ? winSignExp : macSignExp;
-
- String signAct = si.getSignatureParts().iterator().next().
- getSignatureDocument().getSignature().getSignatureValue().getStringValue();
- assertEquals(signExp, signAct);
- }
- }
-
- @Test
- void office2007prettyPrintedRels() throws Exception {
- try (OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ)) {
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- boolean isValid = si.verifySignature();
- assertTrue(isValid);
- }
- }
-
- @Test
- void getSignerUnsigned() throws Exception {
- String[] testFiles = {
- "hello-world-unsigned.docx",
- "hello-world-unsigned.pptx",
- "hello-world-unsigned.xlsx",
- "hello-world-office-2010-technical-preview-unsigned.docx"
- };
-
- for (String testFile : testFiles) {
- List<X509Certificate> result = new ArrayList<>();
- try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
- pkg.revert();
- }
- assertNotNull(result);
- assertTrue(result.isEmpty());
- }
- }
-
- @Test
- void getSigner() throws Exception {
- String[] testFiles = {
- "hyperlink-example-signed.docx",
- "hello-world-signed.docx",
- "hello-world-signed.pptx",
- "hello-world-signed.xlsx",
- "hello-world-office-2010-technical-preview.docx",
- "ms-office-2010-signed.docx",
- "ms-office-2010-signed.pptx",
- "ms-office-2010-signed.xlsx",
- "Office2010-SP1-XAdES-X-L.docx",
- "signed.docx"
- };
-
- for (String testFile : testFiles) {
- try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- List<X509Certificate> result = new ArrayList<>();
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
-
- assertNotNull(result);
- assertEquals(1, result.size(), "test-file: " + testFile);
- X509Certificate signer = result.get(0);
- LOG.atDebug().log("signer: {}", signer.getSubjectX500Principal());
-
- boolean b = si.verifySignature();
- assertTrue(b, "test-file: " + testFile);
- pkg.revert();
- }
- }
- }
-
- @Test
- void getMultiSigners() throws Exception {
- String testFile = "hello-world-signed-twice.docx";
- try (OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ)) {
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- List<X509Certificate> result = new ArrayList<>();
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
-
- assertNotNull(result);
- assertEquals(2, result.size(), "test-file: " + testFile);
- X509Certificate signer1 = result.get(0);
- X509Certificate signer2 = result.get(1);
- LOG.atDebug().log("signer 1: {}", signer1.getSubjectX500Principal());
- LOG.atDebug().log("signer 2: {}", signer2.getSubjectX500Principal());
-
- boolean b = si.verifySignature();
- assertTrue(b, "test-file: " + testFile);
- pkg.revert();
- }
- }
-
- @Test
- void testSignSpreadsheet() throws Exception {
- String testFile = "hello-world-unsigned.xlsx";
- try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
- sign(pkg);
- }
- }
-
- private static class CommitableWorkbook extends XSSFWorkbook {
- CommitableWorkbook(OPCPackage pkg) throws IOException {
- super(pkg);
- }
- public void commit() throws IOException {
- super.commit();
- }
- }
-
- @Test
- void testManipulation() throws Exception {
- // sign & validate
- String testFile = "hello-world-unsigned.xlsx";
- try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
- sign(pkg);
-
- // manipulate
- try (CommitableWorkbook wb = new CommitableWorkbook(pkg)) {
- wb.setSheetName(0, "manipulated");
- // ... I don't know, why commit is protected ...
- wb.commit();
-
- // todo: test a manipulation on a package part, which is not signed
- // ... maybe in combination with #56164
-
- // validate
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- boolean b = si.verifySignature();
- assertFalse(b, "signature should be broken");
- }
- }
- }
-
- @Test
- void testSignSpreadsheetWithSignatureInfo() throws Exception {
- initKeyPair();
- String testFile = "hello-world-unsigned.xlsx";
- try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
- SignatureConfig sic = new SignatureConfig();
- sic.setKey(keyPair.getPrivate());
- sic.setSigningCertificateChain(Collections.singletonList(x509));
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- // hash > sha1 doesn't work in excel viewer ...
- si.confirmSignature();
- List<X509Certificate> result = new ArrayList<>();
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
- assertEquals(1, result.size());
- }
- }
-
- @Test
- void testSignEnvelopingDocument() throws Exception {
- String testFile = "hello-world-unsigned.xlsx";
- File sigCopy = testdata.getFile(testFile);
- ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
-
- final String execTimestr;
-
-
- try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {
-
- initKeyPair();
- final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
-
- // setup
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setKey(keyPair.getPrivate());
-
- /*
- * We need at least 2 certificates for the XAdES-C complete certificate
- * refs construction.
- */
- List<X509Certificate> certificateChain = new ArrayList<>();
- certificateChain.add(x509);
- certificateChain.add(x509);
- signatureConfig.setSigningCertificateChain(certificateChain);
-
- signatureConfig.addSignatureFacet(new OOXMLSignatureFacet());
- signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet());
- signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet());
- signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
- signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());
-
- // check for internet, no error means it works
- boolean mockTsp = (getAccessError("http://timestamp.comodoca.com/rfc3161", true, 10000) != null);
-
- // http://timestamping.edelweb.fr/service/tsp
- // http://tsa.belgium.be/connect
- // http://timestamp.comodoca.com/authenticode
- // http://timestamp.comodoca.com/rfc3161
- // http://services.globaltrustfinder.com/adss/tsa
- signatureConfig.setTspUrl("http://timestamp.comodoca.com/rfc3161");
- signatureConfig.setTspRequestPolicy(null); // comodoca request fails, if default policy is set ...
- signatureConfig.setTspOldProtocol(false);
-
- signatureConfig.setXadesDigestAlgo(HashAlgorithm.sha512);
- signatureConfig.setXadesRole("Xades Reviewer");
- signatureConfig.setSignatureDescription("test xades signature");
-
- execTimestr = signatureConfig.formatExecutionTime();
-
- //set proxy info if any
- String proxy = System.getProperty("http_proxy");
- if (proxy != null && proxy.trim().length() > 0) {
- signatureConfig.setProxyUrl(proxy);
- }
-
- if (mockTsp) {
- TimeStampService tspService = (signatureInfo, data, revocationData) -> {
- revocationData.addCRL(crl);
- return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
- };
- signatureConfig.setTspService(tspService);
- } else {
- TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
- for (X509Certificate certificate : validateChain) {
- LOG.atDebug().log("certificate: {}", certificate.getSubjectX500Principal());
- LOG.atDebug().log("validity: {} - {}", certificate.getNotBefore(), certificate.getNotAfter());
- }
- };
- signatureConfig.setTspValidator(tspValidator);
- signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb"));
- }
-
- final RevocationData revocationData = new RevocationData();
- revocationData.addCRL(crl);
- OCSPResp ocspResp = createOcspResp(x509, x509, x509, keyPair.getPrivate(), cal.getTimeInMillis());
- revocationData.addOCSP(ocspResp.getEncoded());
-
- RevocationDataService revocationDataService = revocationChain -> revocationData;
- signatureConfig.setRevocationDataService(revocationDataService);
-
- // operate
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(signatureConfig);
- try {
- si.confirmSignature();
- } catch (RuntimeException e) {
- // only allow a ConnectException because of timeout, we see this in Jenkins from time to time...
- if (e.getCause() == null) {
- throw e;
- }
- if ((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException)) {
- assumeFalse(e.getCause().getMessage().contains("timed out"),
- "Only allowing ConnectException with 'timed out' as message here, but had: " + e);
- } else if (e.getCause() instanceof IOException) {
- assumeFalse(e.getCause().getMessage().contains("Error contacting TSP server"),
- "Only allowing IOException with 'Error contacting TSP server' as message here, but had: " + e);
- } else if (e.getCause() instanceof RuntimeException) {
- assumeFalse(e.getCause().getMessage().contains("This site is cur"),
- "Only allowing RuntimeException with 'This site is cur' as message here, but had: " + e);
- }
- throw e;
- }
-
- // verify
- Iterator<SignaturePart> spIter = si.getSignatureParts().iterator();
- assertTrue(spIter.hasNext(), "Had: " + pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN));
- SignaturePart sp = spIter.next();
- boolean valid = sp.validate();
- assertTrue(valid);
-
- SignatureDocument sigDoc = sp.getSignatureDocument();
- String declareNS =
- "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
- + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; ";
-
- String digestValXQuery = declareNS +
- "$this/ds:Signature/ds:SignedInfo/ds:Reference";
- for (ReferenceType rt : (ReferenceType[]) sigDoc.selectPath(digestValXQuery)) {
- assertNotNull(rt.getDigestValue());
- assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());
- }
-
- String certDigestXQuery = declareNS +
- "$this//xades:SigningCertificate/xades:Cert/xades:CertDigest";
- XmlObject[] xoList = sigDoc.selectPath(certDigestXQuery);
- assertEquals(xoList.length, 1);
- DigestAlgAndValueType certDigest = (DigestAlgAndValueType) xoList[0];
- assertNotNull(certDigest.getDigestValue());
-
- String qualPropXQuery = declareNS +
- "$this/ds:Signature/ds:Object/xades:QualifyingProperties";
- xoList = sigDoc.selectPath(qualPropXQuery);
- assertEquals(xoList.length, 1);
- QualifyingPropertiesType qualProp = (QualifyingPropertiesType) xoList[0];
- boolean qualPropXsdOk = qualProp.validate();
- assertTrue(qualPropXsdOk);
-
- pkg.save(bos);
- }
-
- try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()))) {
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setUpdateConfigOnValidate(true);
-
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(signatureConfig);
-
- assertTrue(si.verifySignature());
-
- assertEquals(HashAlgorithm.sha512, signatureConfig.getXadesDigestAlgo());
- assertEquals("Xades Reviewer", signatureConfig.getXadesRole());
- assertEquals("test xades signature", signatureConfig.getSignatureDescription());
- assertEquals(execTimestr, signatureConfig.formatExecutionTime());
- }
- }
-
- public static String getAccessError(String destinationUrl, boolean fireRequest, int timeout) {
- URL url;
- try {
- url = new URL(destinationUrl);
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException("Invalid destination URL", e);
- }
-
- HttpURLConnection conn = null;
- try {
- conn = (HttpURLConnection) url.openConnection();
-
- // set specified timeout if non-zero
- if(timeout != 0) {
- conn.setConnectTimeout(timeout);
- conn.setReadTimeout(timeout);
- }
-
- conn.setDoOutput(false);
- conn.setDoInput(true);
-
- /* if connecting is not possible this will throw a connection refused exception */
- conn.connect();
-
- if (fireRequest) {
- conn.getInputStream().close();
- }
- /* if connecting is possible we return true here */
- return null;
-
- } catch (IOException e) {
- /* exception is thrown -> server not available */
- return e.getClass().getName() + ": " + e.getMessage();
- } finally {
- if (conn != null) {
- conn.disconnect();
- }
- }
- }
-
- @Test
- void testCertChain() throws Exception {
- final boolean isIBM = System.getProperty("java.vendor").contains("IBM");
-
- KeyStore keystore = KeyStore.getInstance("PKCS12");
- String password = "test";
- try (InputStream is = testdata.openResourceAsStream("chaintest.pfx")) {
- keystore.load(is, password.toCharArray());
- }
-
- Key key = keystore.getKey("poitest", password.toCharArray());
- Certificate[] chainList = keystore.getCertificateChain("poitest");
- List<X509Certificate> certChain = new ArrayList<>();
- for (Certificate c : chainList) {
- certChain.add((X509Certificate)c);
- }
- x509 = certChain.get(0);
- keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
-
- String testFile = "hello-world-unsigned.xlsx";
- try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
-
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setKey(keyPair.getPrivate());
- signatureConfig.setSigningCertificateChain(certChain);
- Calendar oldCal = LocaleUtil.getLocaleCalendar(2007, 7, 1);
- signatureConfig.setExecutionTime(oldCal.getTime());
- signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
-
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(signatureConfig);
-
- si.confirmSignature();
-
- for (SignaturePart sp : si.getSignatureParts()) {
- assertTrue(sp.validate(), "Could not validate");
- X509Certificate signer = sp.getSigner();
- assertNotNull(signer, "signer undefined?!");
- List<X509Certificate> certChainRes = sp.getCertChain();
-
- // IBM JDK is still buggy, even after fix for APAR IJ21985
- int exp = isIBM ? 1 : 3;
- assertEquals(exp, certChainRes.size());
- }
-
- }
- }
-
- @Test
- void testNonSha1() throws Exception {
- String testFile = "hello-world-unsigned.xlsx";
- initKeyPair();
-
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setKey(keyPair.getPrivate());
- signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-
- HashAlgorithm[] testAlgo = {HashAlgorithm.sha224, HashAlgorithm.sha256
- , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160};
-
- for (HashAlgorithm ha : testAlgo) {
- signatureConfig.setDigestAlgo(ha);
- try (OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE)) {
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(signatureConfig);
-
- si.confirmSignature();
- boolean b = si.verifySignature();
- assertTrue(b, "Signature not correctly calculated for " + ha);
- } catch (EncryptedDocumentException e) {
- assumeTrue(e.getMessage().startsWith("Export Restrictions"));
- }
- }
- }
-
- @Test
- void bug58630() throws Exception {
- // test deletion of sheet 0 and signing
- File tpl = copy(testdata.getFile("bug58630.xlsx"));
- try (SXSSFWorkbook wb1 = new SXSSFWorkbook((XSSFWorkbook)WorkbookFactory.create(tpl), 10)) {
- wb1.setCompressTempFiles(true);
- wb1.removeSheetAt(0);
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- wb1.write(os);
-
- try (OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(os.toByteArray()))) {
- initKeyPair();
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setKey(keyPair.getPrivate());
- signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(signatureConfig);
- si.confirmSignature();
- assertTrue(si.verifySignature(), "invalid signature");
- }
- }
- }
-
- @Test
- void testMultiSign() throws Exception {
- cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
- cal.clear();
- cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
- cal.set(2018, Calendar.DECEMBER, 14);
-
- // test signing with separate opened packages
- File tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
- try (OPCPackage pkg = OPCPackage.open(tpl)) {
- signPkg63011(pkg, "bug63011_key1.pem", true);
- }
-
- try (OPCPackage pkg = OPCPackage.open(tpl)) {
- signPkg63011(pkg, "bug63011_key2.pem", true);
- }
-
- verifyPkg63011(tpl, true);
-
- // test signing with single opened package
- tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
- try (OPCPackage pkg = OPCPackage.open(tpl)) {
- signPkg63011(pkg, "bug63011_key1.pem", true);
- signPkg63011(pkg, "bug63011_key2.pem", true);
- }
-
- verifyPkg63011(tpl, true);
-
- try (OPCPackage pkg = OPCPackage.open(tpl)) {
- signPkg63011(pkg, "bug63011_key1.pem", true);
- signPkg63011(pkg, "bug63011_key2.pem", false);
- }
-
- verifyPkg63011(tpl, false);
- }
-
- private void verifyPkg63011(File tpl, boolean multi) throws InvalidFormatException, IOException {
- try (OPCPackage pkg = OPCPackage.open(tpl, PackageAccess.READ)) {
- SignatureConfig sic = new SignatureConfig();
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- List<X509Certificate> result = new ArrayList<>();
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
-
- assertNotNull(result);
-
- if (multi) {
- assertEquals(2, result.size());
- assertEquals("CN=Muj Klic", result.get(0).getSubjectDN().toString());
- assertEquals("CN=My Second key", result.get(1).getSubjectDN().toString());
- } else {
- assertEquals(1, result.size());
- assertEquals("CN=My Second key", result.get(0).getSubjectDN().toString());
- }
-
- assertTrue(si.verifySignature());
- pkg.revert();
- }
- }
-
- private void signPkg63011(OPCPackage pkg, String pemFile, boolean multi)
- throws IOException, CertificateException, XMLSignatureException, MarshalException {
- assertNotNull(pkg);
- initKeyFromPEM(testdata.getFile(pemFile));
-
- SignatureConfig config = new SignatureConfig();
- config.setKey(keyPair.getPrivate());
- config.setSigningCertificateChain(Collections.singletonList(x509));
- config.setExecutionTime(cal.getTime());
- config.setAllowMultipleSignatures(multi);
-
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(config);
- si.confirmSignature();
- }
-
- @Test
- void testRetrieveCertificate() throws InvalidFormatException, IOException {
- SignatureConfig sic = new SignatureConfig();
- final File file = testdata.getFile("PPT2016withComment.pptx");
- try (final OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ)) {
- sic.setUpdateConfigOnValidate(true);
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- assertTrue(si.verifySignature());
- }
-
- final List<X509Certificate> certs = sic.getSigningCertificateChain();
- assertEquals(1, certs.size());
- assertEquals("CN=Test", certs.get(0).getSubjectDN().getName());
- assertEquals("SuperDuper-Reviewer", sic.getXadesRole());
- assertEquals("Purpose for signing", sic.getSignatureDescription());
- assertEquals("2018-06-10T09:00:54Z", sic.formatExecutionTime());
- assertEquals(CanonicalizationMethod.INCLUSIVE, sic.getCanonicalizationMethod());
- }
-
- private interface XmlDocumentPackageInit {
- POIXMLDocument init(SignatureLine line, OPCPackage pkg) throws IOException, XmlException;
- }
-
- @Test
- void testSignatureImage() throws Exception {
- initKeyPair();
-
- List<Supplier<SignatureLine>> lines = Arrays.asList(XSSFSignatureLine::new, XWPFSignatureLine::new);
- for (Supplier<SignatureLine> sup : lines) {
- SignatureLine line = sup.get();
- line.setSuggestedSigner("Jack Sparrow");
- line.setSuggestedSigner2("Captain");
- line.setSuggestedSignerEmail("jack.bl@ck.perl");
- line.setInvalidStamp("Bungling!");
- line.setPlainSignature(testdata.readFile("jack-sign.emf"));
-
- String[] ext = { "" };
- BiFunction<SignatureLine,String[],POIXMLDocument> init =
- (line instanceof XSSFSignatureLine)
- ? this::initSignatureImageXSSF
- : this::initSignatureImageXWPF;
-
- File signDoc;
- try (POIXMLDocument xmlDoc = init.apply(line,ext)) {
- signDoc = TempFile.createTempFile("visual-signature", ext[0]);
- try (FileOutputStream fos = new FileOutputStream(signDoc)) {
- xmlDoc.write(fos);
- }
- }
-
- try (OPCPackage pkg = OPCPackage.open(signDoc, PackageAccess.READ_WRITE)) {
- SignatureConfig sic = new SignatureConfig();
- sic.setKey(keyPair.getPrivate());
- sic.setSigningCertificateChain(Collections.singletonList(x509));
-
- line.updateSignatureConfig(sic);
-
- sic.setDigestAlgo(HashAlgorithm.sha1);
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkg);
- si.setSignatureConfig(sic);
- // hash > sha1 doesn't work in excel viewer ...
- si.confirmSignature();
- } catch (java.util.ServiceConfigurationError e) {
- assumeFalse(true, "running on module-path / JPMS and batik is \"kaputt\" WRT JPMS");
- }
-
- XmlDocumentPackageInit reinit =
- (line instanceof XSSFSignatureLine)
- ? this::initSignatureImageXSSF
- : this::initSignatureImageXWPF;
-
- try (OPCPackage pkg = OPCPackage.open(signDoc, PackageAccess.READ)) {
- SignatureLine line2 = sup.get();
- try (POIXMLDocument doc = reinit.init(line2, pkg)) {
- assertNotNull(doc);
-
- line2.parse();
- assertEquals(line.getSuggestedSigner(), line2.getSuggestedSigner());
- assertEquals(line.getSuggestedSigner2(), line2.getSuggestedSigner2());
- assertEquals(line.getSuggestedSignerEmail(), line2.getSuggestedSignerEmail());
- }
-
- pkg.revert();
- }
- }
- }
-
- private XWPFDocument initSignatureImageXWPF(SignatureLine line, String[] ext) {
- XWPFDocument doc = new XWPFDocument();
- ((XWPFSignatureLine)line).add(doc.createParagraph());
- ext[0] = ".docx";
- return doc;
- }
-
- private XWPFDocument initSignatureImageXWPF(SignatureLine line, OPCPackage pkg) throws IOException, XmlException {
- XWPFDocument doc = new XWPFDocument(pkg);
- ((XWPFSignatureLine)line).parse(doc);
- return doc;
- }
-
- private XSSFWorkbook initSignatureImageXSSF(SignatureLine line, String[] ext) {
- XSSFWorkbook xls = new XSSFWorkbook();
- XSSFSheet sheet = xls.createSheet();
- XSSFClientAnchor anchor = new XSSFClientAnchor(0,0,0,0,3,3,8,13);
- ((XSSFSignatureLine)line).add(sheet, anchor);
- ext[0] = ".xlsx";
- return xls;
- }
-
- private XSSFWorkbook initSignatureImageXSSF(SignatureLine line, OPCPackage pkg) throws IOException, XmlException {
- XSSFWorkbook xls = new XSSFWorkbook(pkg);
- ((XSSFSignatureLine)line).parse(xls.getSheetAt(0));
- return xls;
- }
-
-
- private SignatureConfig prepareConfig(String pfxInput) throws Exception {
- initKeyPair(pfxInput);
-
- SignatureConfig signatureConfig = new SignatureConfig();
- signatureConfig.setKey(keyPair.getPrivate());
- signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
- signatureConfig.setExecutionTime(cal.getTime());
- signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
-
- return signatureConfig;
- }
-
- private void sign(OPCPackage pkgCopy) throws Exception {
- int signerCount = 1;
-
- SignatureConfig signatureConfig = prepareConfig(null);
-
- SignatureInfo si = new SignatureInfo();
- si.setOpcPackage(pkgCopy);
- si.setSignatureConfig(signatureConfig);
-
- final Document document = DocumentHelper.createDocument();
- final DOMSignContext xmlSignContext = si.createXMLSignContext(document);
-
- // operate
- final DOMSignedInfo signedInfo = si.preSign(xmlSignContext);
-
- // verify
- assertNotNull(signedInfo);
- assertEquals("Office OpenXML Document", signatureConfig.getSignatureDescription());
-
- // setup: key material, signature value
- final String signatureValue = si.signDigest(xmlSignContext, signedInfo);
-
- // operate: postSign
- si.postSign(xmlSignContext, signatureValue);
-
- // verify: signature
- si.setOpcPackage(pkgCopy);
- List<X509Certificate> result = new ArrayList<>();
- for (SignaturePart sp : si.getSignatureParts()) {
- if (sp.validate()) {
- result.add(sp.getSigner());
- }
- }
- assertEquals(signerCount, result.size());
- }
-
- private void initKeyPair() throws Exception {
- initKeyPair(null);
- }
-
- private void initKeyPair(String pfxInput) throws Exception {
- final String alias = "Test";
- final char[] password = "test".toCharArray();
- File file = new File("build/test.pfx");
- assertTrue(file.getParentFile().exists() || file.getParentFile().mkdir());
-
- KeyStore keystore = KeyStore.getInstance("PKCS12");
-
- if (pfxInput != null) {
- try (InputStream fis = new ByteArrayInputStream(RawDataUtil.decompress(pfxInput))) {
- keystore.load(fis, password);
- }
- } else if (file.exists()) {
- try (InputStream fis = new FileInputStream(file)) {
- keystore.load(fis, password);
- }
- } else {
- keystore.load(null, password);
- }
-
- if (keystore.isKeyEntry(alias)) {
- Key key = keystore.getKey(alias, password);
- x509 = (X509Certificate)keystore.getCertificate(alias);
- keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
- } else {
- keyPair = generateKeyPair();
- Date notBefore = cal.getTime();
- Calendar cal2 = (Calendar)cal.clone();
- cal2.add(Calendar.YEAR, 1);
- Date notAfter = cal2.getTime();
- KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature);
-
- x509 = generateCertificate(keyPair.getPublic(), notBefore, notAfter, keyPair.getPrivate(), keyUsage);
-
- keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
-
- if (pfxInput == null) {
- try (FileOutputStream fos = new FileOutputStream(file)) {
- keystore.store(fos, password);
- }
- }
- }
- }
-
- private void initKeyFromPEM(File pemFile) throws IOException, CertificateException {
- // see https://stackoverflow.com/questions/11787571/how-to-read-pem-file-to-get-private-and-public-key
- PrivateKey key = null;
- x509 = null;
-
- try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(pemFile), StandardCharsets.ISO_8859_1))) {
- PEMParser parser = new PEMParser(br);
- for (Object obj; (obj = parser.readObject()) != null; ) {
- if (obj instanceof PrivateKeyInfo) {
- key = new JcaPEMKeyConverter().setProvider("BC").getPrivateKey((PrivateKeyInfo)obj);
- } else if (obj instanceof X509CertificateHolder) {
- x509 = new JcaX509CertificateConverter().setProvider("BC").getCertificate((X509CertificateHolder)obj);
- }
- }
- }
-
- if (key != null && x509 != null) {
- keyPair = new KeyPair(x509.getPublicKey(), key);
- }
- }
-
- private static File copy(File input) throws IOException {
- String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1");
- if (extension.isEmpty()) {
- extension = ".zip";
- }
-
- // ensure that we create the "build" directory as it might not be existing
- // in the Sonar Maven runs where we are at a different source directory
- File buildDir = new File("build");
- if(!buildDir.exists()) {
- assertTrue(buildDir.mkdirs(), "Failed to create " + buildDir.getAbsolutePath());
- }
- File tmpFile = new File(buildDir, "sigtest"+extension);
-
- try (OutputStream fos = new FileOutputStream(tmpFile)) {
- try (InputStream fis = new FileInputStream(input)) {
- IOUtils.copy(fis, fos);
- }
- }
-
- return tmpFile;
- }
-
- private static KeyPair generateKeyPair() throws Exception {
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- SecureRandom random = new SecureRandom();
- keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024,
- RSAKeyGenParameterSpec.F4), random);
- return keyPairGenerator.generateKeyPair();
- }
-
- private static X509Certificate generateCertificate(PublicKey subjectPublicKey,
- Date notBefore, Date notAfter,
- PrivateKey issuerPrivateKey,
- KeyUsage keyUsage)
- throws IOException, OperatorCreationException, CertificateException {
- final String signatureAlgorithm = "SHA1withRSA";
- final String subjectDn = "CN=Test";
- X500Name issuerName = new X500Name(subjectDn);
-
- RSAPublicKey rsaPubKey = (RSAPublicKey)subjectPublicKey;
- RSAKeyParameters rsaSpec = new RSAKeyParameters(false, rsaPubKey.getModulus(), rsaPubKey.getPublicExponent());
-
- SubjectPublicKeyInfo subjectPublicKeyInfo =
- SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaSpec);
-
- DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
- .setProvider("BC").build().get(CertificateID.HASH_SHA1);
-
- X509v3CertificateBuilder certificateGenerator = new X509v3CertificateBuilder(
- issuerName
- , new BigInteger(128, new SecureRandom())
- , notBefore
- , notAfter
- , new X500Name(subjectDn)
- , subjectPublicKeyInfo
- );
-
- X509ExtensionUtils exUtils = new X509ExtensionUtils(digestCalc);
- SubjectKeyIdentifier subKeyId = exUtils.createSubjectKeyIdentifier(subjectPublicKeyInfo);
- AuthorityKeyIdentifier autKeyId = exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
-
- certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
- certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
-
- BasicConstraints bc = new BasicConstraints(0);
- certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
-
- if (null != keyUsage) {
- certificateGenerator.addExtension(Extension.keyUsage, true, keyUsage);
- }
-
- JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(signatureAlgorithm);
- signerBuilder.setProvider("BC");
-
- X509CertificateHolder certHolder =
- certificateGenerator.build(signerBuilder.build(issuerPrivateKey));
-
- /*
- * Next certificate factory trick is needed to make sure that the
- * certificate delivered to the caller is provided by the default
- * security provider instead of BouncyCastle. If we don't do this trick
- * we might run into trouble when trying to use the CertPath validator.
- */
- // CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- // certificate = (X509Certificate) certificateFactory
- // .generateCertificate(new ByteArrayInputStream(certificate
- // .getEncoded()));
- return new JcaX509CertificateConverter().getCertificate(certHolder);
- }
-
- private static X509CRL generateCrl(X509Certificate issuer, PrivateKey issuerPrivateKey)
- throws CertificateEncodingException, IOException, CRLException, OperatorCreationException {
-
- X509CertificateHolder holder = new X509CertificateHolder(issuer.getEncoded());
- X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(holder.getIssuer(), new Date());
- crlBuilder.setNextUpdate(new Date(new Date().getTime() + 100000));
- JcaContentSignerBuilder contentBuilder = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC");
-
- CRLNumber crlNumber = new CRLNumber(new BigInteger("1234"));
-
- crlBuilder.addExtension(Extension.cRLNumber, false, crlNumber);
- X509CRLHolder x509Crl = crlBuilder.build(contentBuilder.build(issuerPrivateKey));
- return new JcaX509CRLConverter().setProvider("BC").getCRL(x509Crl);
- }
-
- private static OCSPResp createOcspResp(X509Certificate certificate,
- X509Certificate issuerCertificate,
- X509Certificate ocspResponderCertificate,
- PrivateKey ocspResponderPrivateKey,
- long nonceTimeinMillis)
- throws Exception {
- DigestCalculator digestCalc = new JcaDigestCalculatorProviderBuilder()
- .setProvider("BC").build().get(CertificateID.HASH_SHA1);
- X509CertificateHolder issuerHolder = new X509CertificateHolder(issuerCertificate.getEncoded());
- CertificateID certId = new CertificateID(digestCalc, issuerHolder, certificate.getSerialNumber());
-
- // request
- //create a nonce to avoid replay attack
- BigInteger nonce = BigInteger.valueOf(nonceTimeinMillis);
- DEROctetString nonceDer = new DEROctetString(nonce.toByteArray());
- Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, nonceDer);
- Extensions exts = new Extensions(ext);
-
- OCSPReqBuilder ocspReqBuilder = new OCSPReqBuilder();
- ocspReqBuilder.addRequest(certId);
- ocspReqBuilder.setRequestExtensions(exts);
- OCSPReq ocspReq = ocspReqBuilder.build();
-
-
- SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo
- (CertificateID.HASH_SHA1, ocspResponderCertificate.getPublicKey().getEncoded());
-
- BasicOCSPRespBuilder basicOCSPRespBuilder = new BasicOCSPRespBuilder(keyInfo, digestCalc);
- basicOCSPRespBuilder.setResponseExtensions(exts);
-
- // request processing
- Req[] requestList = ocspReq.getRequestList();
- for (Req ocspRequest : requestList) {
- CertificateID certificateID = ocspRequest.getCertID();
- CertificateStatus certificateStatus = CertificateStatus.GOOD;
- basicOCSPRespBuilder.addResponse(certificateID, certificateStatus);
- }
-
- // basic response generation
- X509CertificateHolder[] chain = null;
- if (!ocspResponderCertificate.equals(issuerCertificate)) {
- // TODO: HorribleProxy can't convert array input params yet
- chain = new X509CertificateHolder[] {
- new X509CertificateHolder(ocspResponderCertificate.getEncoded()),
- issuerHolder
- };
- }
-
- ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA")
- .setProvider("BC").build(ocspResponderPrivateKey);
- BasicOCSPResp basicOCSPResp = basicOCSPRespBuilder.build(contentSigner, chain, new Date(nonceTimeinMillis));
-
-
- OCSPRespBuilder ocspRespBuilder = new OCSPRespBuilder();
-
- return ocspRespBuilder.build(OCSPRespBuilder.SUCCESSFUL, basicOCSPResp);
- }
- }
|