merge trunk

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1849036 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2018-12-16 16:51:08 +00:00
commit abe662db86
21 changed files with 927 additions and 405 deletions

View File

@ -91,7 +91,7 @@ subprojects {
// See https://github.com/melix/japicmp-gradle-plugin // See https://github.com/melix/japicmp-gradle-plugin
apply plugin: 'me.champeau.gradle.japicmp' apply plugin: 'me.champeau.gradle.japicmp'
version = '4.0.1-SNAPSHOT' version = '4.0.2-SNAPSHOT'
ext { ext {
japicmpversion = '4.0.0' japicmpversion = '4.0.0'
} }
@ -233,6 +233,11 @@ project('ooxml') {
compile 'org.bouncycastle:bcpkix-jdk15on:1.60' compile 'org.bouncycastle:bcpkix-jdk15on:1.60'
compile 'com.github.virtuald:curvesapi:1.05' compile 'com.github.virtuald:curvesapi:1.05'
// compile only, don't add it to our dist as it blows up the size
compile 'org.apache.xmlgraphics:batik-all:1.10'
compile 'xml-apis:xml-apis-ext:1.3.04'
compile 'org.apache.xmlgraphics:xmlgraphics-commons:2.3'
// for ooxml-lite, should we move this somewhere else? // for ooxml-lite, should we move this somewhere else?
compile 'junit:junit:4.12' compile 'junit:junit:4.12'

View File

@ -217,6 +217,14 @@ under the License.
<property name="dsig.sl4j-api.jar" location="${compile.lib}/slf4j-api-1.7.25.jar"/> <property name="dsig.sl4j-api.jar" location="${compile.lib}/slf4j-api-1.7.25.jar"/>
<property name="dsig.sl4j-api.url" value="${repository.m2}/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar"/> <property name="dsig.sl4j-api.url" value="${repository.m2}/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar"/>
<!-- svg/batik libs - not part of the distribution -->
<property name="svg.batik-all.url" value="${repository.m2}/maven2/org/apache/xmlgraphics/batik-all/1.10/batik-all-1.10.jar"/>
<property name="svg.batik-all.jar" value="${compile.lib}/batik-all-1.10.jar"/>
<property name="svg.xml-apis-ext.url" value="${repository.m2}/maven2/xml-apis/xml-apis-ext/1.3.04/xml-apis-ext-1.3.04.jar"/>
<property name="svg.xml-apis-ext.jar" value="${compile.lib}/xml-apis-ext-1.3.04.jar"/>
<property name="svg.xmlgraphics-commons.url" value="${repository.m2}/maven2/org/apache/xmlgraphics/xmlgraphics-commons/2.3/xmlgraphics-commons-2.3.jar"/>
<property name="svg.xmlgraphics-commons.jar" value="${compile.lib}/xmlgraphics-commons-2.3.jar"/>
<!-- jars in the ooxml-lib directory, see the fetch-ooxml-jars target--> <!-- jars in the ooxml-lib directory, see the fetch-ooxml-jars target-->
<property name="ooxml.curvesapi.jar" location="${ooxml.lib}/curvesapi-1.05.jar"/> <property name="ooxml.curvesapi.jar" location="${ooxml.lib}/curvesapi-1.05.jar"/>
<property name="ooxml.curvesapi.url" <property name="ooxml.curvesapi.url"
@ -395,6 +403,12 @@ under the License.
<pathelement location="${scratchpad.output.dir}" unless:true="${scratchpad.ignore}"/> <pathelement location="${scratchpad.output.dir}" unless:true="${scratchpad.ignore}"/>
</path> </path>
<path id="batik.classpath">
<pathelement location="${svg.batik-all.jar}"/>
<pathelement location="${svg.xml-apis-ext.jar}"/>
<pathelement location="${svg.xmlgraphics-commons.jar}"/>
</path>
<path id="ooxml-lite.classpath"> <path id="ooxml-lite.classpath">
<path refid="ooxml.base.classpath"/> <path refid="ooxml.base.classpath"/>
<!-- instead of ooxml-xsds.jar use the filtered classes--> <!-- instead of ooxml-xsds.jar use the filtered classes-->
@ -402,11 +416,13 @@ under the License.
<pathelement location="${ooxml.output.dir}"/> <pathelement location="${ooxml.output.dir}"/>
<pathelement location="${ooxml.output.test.dir}"/> <pathelement location="${ooxml.output.test.dir}"/>
<pathelement location="${main.output.test.dir}"/> <pathelement location="${main.output.test.dir}"/>
<path refid="batik.classpath"/>
</path> </path>
<path id="ooxml.classpath"> <path id="ooxml.classpath">
<pathelement location="${ooxml.xsds.jar}"/> <pathelement location="${ooxml.xsds.jar}"/>
<path refid="ooxml.base.classpath"/> <path refid="ooxml.base.classpath"/>
<path refid="batik.classpath"/>
</path> </path>
<path id="ooxml.lite.verify.classpath"> <path id="ooxml.lite.verify.classpath">
@ -777,6 +793,9 @@ under the License.
<available file="${ooxml.test.reflections.jar}"/> <available file="${ooxml.test.reflections.jar}"/>
<available file="${ooxml.test.guava.jar}"/> <available file="${ooxml.test.guava.jar}"/>
<available file="${ooxml.test.javassist.jar}"/> <available file="${ooxml.test.javassist.jar}"/>
<available file="${svg.xml-apis-ext.jar}"/>
<available file="${svg.batik-all.jar}"/>
<available file="${svg.xmlgraphics-commons.jar}"/>
</and> </and>
<isset property="disconnected"/> <isset property="disconnected"/>
</or> </or>
@ -791,6 +810,9 @@ under the License.
<downloadfile src="${ooxml.test.reflections.url}" dest="${ooxml.test.reflections.jar}"/> <downloadfile src="${ooxml.test.reflections.url}" dest="${ooxml.test.reflections.jar}"/>
<downloadfile src="${ooxml.test.guava.url}" dest="${ooxml.test.guava.jar}"/> <downloadfile src="${ooxml.test.guava.url}" dest="${ooxml.test.guava.jar}"/>
<downloadfile src="${ooxml.test.javassist.url}" dest="${ooxml.test.javassist.jar}"/> <downloadfile src="${ooxml.test.javassist.url}" dest="${ooxml.test.javassist.jar}"/>
<downloadfile src="${svg.batik-all.url}" dest="${svg.batik-all.jar}"/>
<downloadfile src="${svg.xml-apis-ext.url}" dest="${svg.xml-apis-ext.jar}"/>
<downloadfile src="${svg.xmlgraphics-commons.url}" dest="${svg.xmlgraphics-commons.jar}"/>
</target> </target>
<target name="check-svn-jars"> <target name="check-svn-jars">
<condition property="svn.jars.present"> <condition property="svn.jars.present">
@ -932,6 +954,7 @@ under the License.
</xmlbean> </xmlbean>
<local name="loaderMethod"/> <local name="loaderMethod"/>
<!-- the space between "public static" is on purpose to prevent double execution -->
<property name="loaderMethod"><![CDATA[ <property name="loaderMethod"><![CDATA[
private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader; private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader;

View File

@ -70,9 +70,7 @@ def poijobs = [
'-Djava.locale.providers=JRE,CLDR'], '-Djava.locale.providers=JRE,CLDR'],
skipcigame: true skipcigame: true
], ],
[ name: 'POI-DSL-IBM-JDK', jdk: 'IBMJDK', trigger: triggerSundays, [ name: 'POI-DSL-IBM-JDK', jdk: 'IBMJDK', trigger: triggerSundays, skipcigame: true
// some OOXML tests fail with strange XML parsing errors and missing JCE unlimited strength requirements
disabled: true, skipcigame: true
], ],
[ name: 'POI-DSL-old-Xerces', trigger: triggerSundays, [ name: 'POI-DSL-old-Xerces', trigger: triggerSundays,
shell: "test -f ${xercesLib} || wget -O ${xercesLib} ${xercesUrl}\n", shell: "test -f ${xercesLib} || wget -O ${xercesLib} ${xercesUrl}\n",

View File

@ -185,5 +185,12 @@
<version>1.19</version> <version>1.19</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<!-- don't add it to the distribution -->
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-all</artifactId>
<version>1.10</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -268,9 +268,7 @@
</goals> </goals>
<configuration> <configuration>
<target> <target>
<property name="xmlbean.sources.dir" <!-- the space between "public static" is on purpose to prevent double execution -->
location="${basedir}/target/generated-sources/xmlbeans"/>
<property name="loaderMethod"><![CDATA[ <property name="loaderMethod"><![CDATA[
private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader; private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader;
@ -285,23 +283,24 @@
public static \2 newInstance\(\) \{]]></property> public static \2 newInstance\(\) \{]]></property>
<fileset id="xsrc" dir="${basedir}/target/generated-sources/xmlbeans" includes="**/*.java" excludes="**/impl/**"/>
<replaceregexp byline="true" <replaceregexp byline="true"
match="(\s*)public static ([^ ]+) newInstance\(\) \{" match="(\s*)public static ([^ ]+) newInstance\(\) \{"
replace="${loaderMethod}"> replace="${loaderMethod}">
<fileset dir="${xmlbean.sources.dir}" includes="**/*.java" <fileset refid="xsrc"/>
excludes="**/impl/**"/>
</replaceregexp> </replaceregexp>
<replace dir="${xmlbean.sources.dir}" includes="**/*.java" <replace>
excludes="**/impl/**"> <fileset refid="xsrc"/>
<replacetoken>org.apache.xmlbeans.XmlBeans.getContextTypeLoader <replacetoken>org.apache.xmlbeans.XmlBeans.getContextTypeLoader
</replacetoken> </replacetoken>
<replacevalue>getTypeLoader</replacevalue> <replacevalue>getTypeLoader</replacevalue>
</replace> </replace>
<!-- remove deprecated warnings, as we prefer the array methods - see #56854 --> <!-- remove deprecated warnings, as we prefer the array methods - see #56854 -->
<replace dir="${xmlbean.sources.dir}" includes="**/*.java" <replace>
excludes="**/impl/**"> <fileset refid="xsrc"/>
<replacetoken><![CDATA[ * @deprecated <replacetoken><![CDATA[ * @deprecated
]]></replacetoken> ]]></replacetoken>
</replace> </replace>

View File

@ -212,6 +212,12 @@ public class TestAllFiles {
HANDLERS.put("spreadsheet/BigSSTRecordCR", new NullFileHandler()); HANDLERS.put("spreadsheet/BigSSTRecordCR", new NullFileHandler());
HANDLERS.put("spreadsheet/test_properties1", new NullFileHandler()); HANDLERS.put("spreadsheet/test_properties1", new NullFileHandler());
// keystore files
HANDLERS.put(".pfx", new NullFileHandler());
HANDLERS.put(".pem", new NullFileHandler());
HANDLERS.put(".jks", new NullFileHandler());
HANDLERS.put(".pkcs12", new NullFileHandler());
Map<String,String> passmap = new HashMap<>(); Map<String,String> passmap = new HashMap<>();
passmap.put("slideshow/Password_Protected-hello.ppt", "hello"); passmap.put("slideshow/Password_Protected-hello.ppt", "hello");
passmap.put("slideshow/Password_Protected-56-hello.ppt", "hello"); passmap.put("slideshow/Password_Protected-56-hello.ppt", "hello");

View File

@ -46,7 +46,10 @@ public interface PictureData {
/** WordPerfect graphics (.wpg) */ /** WordPerfect graphics (.wpg) */
WPG(-1,12,"image/x-wpg",".wpg"), WPG(-1,12,"image/x-wpg",".wpg"),
/** Microsoft Windows Media Photo image (.wdp) */ /** Microsoft Windows Media Photo image (.wdp) */
WDP(-1,13,"image/vnd.ms-photo",".wdp"); WDP(-1,13,"image/vnd.ms-photo",".wdp"),
/** Scalable vector graphics (.svg) - supported by Office 2016 and higher */
SVG(-1, -1, "image/svg+xml", ".svg")
;
public final int nativeId, ooxmlId; public final int nativeId, ooxmlId;
public final String contentType,extension; public final String contentType,extension;

View File

@ -0,0 +1,62 @@
/* ====================================================================
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.
==================================================================== */
package org.apache.poi.poifs.crypt.dsig;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ooxml.POIXMLRelation;
import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
public class DSigRelation extends POIXMLRelation {
/**
* A map to lookup POIXMLRelation by its relation type
*/
private static final Map<String, DSigRelation> _table = new HashMap<>();
public static final DSigRelation ORIGIN_SIGS = new DSigRelation(
ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART,
PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN,
"/_xmlsignatures/origin.sigs", null
);
public static final DSigRelation SIG = new DSigRelation(
ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART,
PackageRelationshipTypes.DIGITAL_SIGNATURE,
"/_xmlsignatures/sig#.xml", null
);
private DSigRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
super(type, rel, defaultName, cls);
_table.put(rel, this);
}
/**
* Get POIXMLRelation by relation type
*
* @param rel relation type, for example,
* <code>http://schemas.openxmlformats.org/officeDocument/2006/relationships/image</code>
* @return registered POIXMLRelation or null if not found
*/
public static DSigRelation getInstance(String rel) {
return _table.get(rel);
}
}

View File

@ -174,6 +174,13 @@ public class SignatureConfig {
*/ */
private boolean updateConfigOnValidate = false; private boolean updateConfigOnValidate = false;
/**
* if true, the signature is added to the existing signatures
*
* @since POI 4.0.2
*/
private boolean allowMultipleSignatures = false;
/** /**
* Inits and checks the config object. * Inits and checks the config object.
@ -1008,4 +1015,25 @@ public class SignatureConfig {
public void setUpdateConfigOnValidate(boolean updateConfigOnValidate) { public void setUpdateConfigOnValidate(boolean updateConfigOnValidate) {
this.updateConfigOnValidate = updateConfigOnValidate; this.updateConfigOnValidate = updateConfigOnValidate;
} }
/**
* @return true, if multiple signatures can be attached
*
* @since POI 4.0.2
*/
public boolean isAllowMultipleSignatures() {
return allowMultipleSignatures;
}
/**
* Activate multiple signatures
*
* @param allowMultipleSignatures if true, the signature will be added,
* otherwise all existing signatures will be replaced by the current
*
* @since POI 4.0.2
*/
public void setAllowMultipleSignatures(boolean allowMultipleSignatures) {
this.allowMultipleSignatures = allowMultipleSignatures;
}
} }

View File

@ -59,7 +59,6 @@ import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
import org.apache.jcp.xml.dsig.internal.dom.DOMSubTreeData; import org.apache.jcp.xml.dsig.internal.dom.DOMSubTreeData;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackagePartName;
@ -377,9 +376,8 @@ public class SignatureInfo implements SignatureConfigurable {
xmlSignContext.setURIDereferencer(uriDereferencer); xmlSignContext.setURIDereferencer(uriDereferencer);
} }
for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) { signatureConfig.getNamespacePrefixes().forEach(xmlSignContext::putNamespacePrefix);
xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
}
xmlSignContext.setDefaultNamespacePrefix(""); xmlSignContext.setDefaultNamespacePrefix("");
// signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS)); // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
@ -516,9 +514,7 @@ public class SignatureInfo implements SignatureConfigurable {
protected void writeDocument(Document document) throws MarshalException { protected void writeDocument(Document document) throws MarshalException {
XmlOptions xo = new XmlOptions(); XmlOptions xo = new XmlOptions();
Map<String,String> namespaceMap = new HashMap<>(); Map<String,String> namespaceMap = new HashMap<>();
for(Map.Entry<String,String> entry : signatureConfig.getNamespacePrefixes().entrySet()){ signatureConfig.getNamespacePrefixes().forEach((k,v) -> namespaceMap.put(v,k));
namespaceMap.put(entry.getValue(), entry.getKey());
}
xo.setSaveSuggestedPrefixes(namespaceMap); xo.setSaveSuggestedPrefixes(namespaceMap);
xo.setUseDefaultNamespace(); xo.setUseDefaultNamespace();
@ -530,43 +526,58 @@ public class SignatureInfo implements SignatureConfigurable {
*/ */
OPCPackage pkg = signatureConfig.getOpcPackage(); OPCPackage pkg = signatureConfig.getOpcPackage();
PackagePartName sigPartName, sigsPartName;
try { try {
// <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
// <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/> // <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs"); final DSigRelation originDesc = DSigRelation.ORIGIN_SIGS;
} catch (InvalidFormatException e) { PackagePartName originPartName = PackagingURIHelper.createPartName(originDesc.getFileName(0));
throw new MarshalException(e);
PackagePart originPart = pkg.getPart(originPartName);
if (originPart == null) {
// touch empty marker file
originPart = pkg.createPart(originPartName, originDesc.getContentType());
pkg.addRelationship(originPartName, TargetMode.INTERNAL, originDesc.getRelation());
} }
// <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
final DSigRelation sigDesc = DSigRelation.SIG;
int nextSigIdx = pkg.getUnusedPartIndex(sigDesc.getDefaultFileName());
if (!signatureConfig.isAllowMultipleSignatures()) {
PackageRelationshipCollection prc = originPart.getRelationshipsByType(sigDesc.getRelation());
for (int i=2; i<nextSigIdx; i++) {
PackagePartName pn = PackagingURIHelper.createPartName(sigDesc.getFileName(i));
for (PackageRelationship rel : prc) {
PackagePart pp = originPart.getRelatedPart(rel);
if (pp.getPartName().equals(pn)) {
originPart.removeRelationship(rel.getId());
prc.removeRelationship(rel.getId());
break;
}
}
pkg.removePart(pkg.getPart(pn));
}
nextSigIdx = 1;
}
PackagePartName sigPartName = PackagingURIHelper.createPartName(sigDesc.getFileName(nextSigIdx));
PackagePart sigPart = pkg.getPart(sigPartName); PackagePart sigPart = pkg.getPart(sigPartName);
if (sigPart == null) { if (sigPart == null) {
sigPart = pkg.createPart(sigPartName, ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART); sigPart = pkg.createPart(sigPartName, sigDesc.getContentType());
originPart.addRelationship(sigPartName, TargetMode.INTERNAL, sigDesc.getRelation());
} else {
sigPart.clear();
} }
try { try (OutputStream os = sigPart.getOutputStream()) {
OutputStream os = sigPart.getOutputStream();
SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS); SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS);
sigDoc.save(os, xo); sigDoc.save(os, xo);
os.close(); }
} catch (Exception e) { } catch (Exception e) {
throw new MarshalException("Unable to write signature document", e); throw new MarshalException("Unable to write signature document", e);
} }
PackagePart sigsPart = pkg.getPart(sigsPartName);
if (sigsPart == null) {
// touch empty marker file
sigsPart = pkg.createPart(sigsPartName, ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART);
}
PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
for (PackageRelationship pr : relCol) {
pkg.removeRelationship(pr.getId());
}
pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
} }
private Element getDsigElement(final Document document, final String localName) { private Element getDsigElement(final Document document, final String localName) {

View File

@ -185,9 +185,7 @@ public class SignaturePart {
final Map<String,String> nsMap = new HashMap<>(); final Map<String,String> nsMap = new HashMap<>();
{ {
for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) { signatureConfig.getNamespacePrefixes().forEach((k,v) -> nsMap.put(v,k));
nsMap.put(me.getValue(), me.getKey());
}
nsMap.put("dsss", MS_DIGSIG_NS); nsMap.put("dsss", MS_DIGSIG_NS);
nsMap.put("ds", XML_DIGSIG_NS); nsMap.put("ds", XML_DIGSIG_NS);
} }

View File

@ -129,9 +129,7 @@ public class KeyInfoSignatureFacet extends SignatureFacet {
DOMSignContext domSignContext = (nextSibling == null) DOMSignContext domSignContext = (nextSibling == null)
? new DOMSignContext(key, n) ? new DOMSignContext(key, n)
: new DOMSignContext(key, n, nextSibling); : new DOMSignContext(key, n, nextSibling);
for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) { signatureConfig.getNamespacePrefixes().forEach(domSignContext::putNamespacePrefix);
domSignContext.putNamespacePrefix(me.getKey(), me.getValue());
}
DOMStructure domStructure = new DOMStructure(n); DOMStructure domStructure = new DOMStructure(n);
domKeyInfo.marshal(domStructure, domSignContext); domKeyInfo.marshal(domStructure, domSignContext);

View File

@ -0,0 +1,136 @@
/* ====================================================================
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.
==================================================================== */
package org.apache.poi.xslf.draw;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.ext.awt.RenderingHintsKeyExt;
import org.apache.batik.ext.awt.image.renderable.ClipRable8Bit;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.XMLResourceDescriptor;
import org.apache.poi.sl.draw.ImageRenderer;
import org.w3c.dom.Document;
public class SVGImageRenderer implements ImageRenderer {
private final GVTBuilder builder = new GVTBuilder();
private final BridgeContext context;
private final SAXSVGDocumentFactory svgFact;
private GraphicsNode svgRoot;
private double alpha = 1.0;
public SVGImageRenderer() {
String parser = XMLResourceDescriptor.getXMLParserClassName();
// TOOO: tell the batik guys to use secure parsing feature
svgFact = new SAXSVGDocumentFactory(parser);
UserAgent agent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(agent);
context = new BridgeContext(agent, loader);
context.setDynamic(true);
}
@Override
public void loadImage(InputStream data, String contentType) throws IOException {
Document document = svgFact.createDocument("", data);
svgRoot = builder.build(context, document);
}
@Override
public void loadImage(byte[] data, String contentType) throws IOException {
loadImage(new ByteArrayInputStream(data), contentType);
}
@Override
public Dimension getDimension() {
Rectangle2D r = svgRoot.getPrimitiveBounds();
return new Dimension((int)Math.ceil(r.getWidth()), (int)Math.ceil(r.getHeight()));
}
@Override
public void setAlpha(double alpha) {
this.alpha = alpha;
}
@Override
public BufferedImage getImage() {
return getImage(getDimension());
}
@Override
public BufferedImage getImage(Dimension dim) {
BufferedImage bi = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) bi.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference(bi));
Dimension dimSVG = getDimension();
double scaleX = dim.getWidth() / dimSVG.getWidth();
double scaleY = dim.getHeight() / dimSVG.getHeight();
g2d.scale(scaleX, scaleY);
svgRoot.paint(g2d);
g2d.dispose();
return bi;
}
@Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) {
return drawImage(graphics, anchor, null);
}
@Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {
if (clip == null) {
svgRoot.setClip(null);
} else {
Rectangle2D clippedRect = new Rectangle2D.Double(
anchor.getX()+clip.left,
anchor.getY()+clip.top,
anchor.getWidth()-(clip.left+clip.right),
anchor.getHeight()-(clip.top+clip.bottom)
);
svgRoot.setClip(new ClipRable8Bit(null, clippedRect));
}
svgRoot.paint(graphics);
return true;
}
}

View File

@ -218,6 +218,8 @@ public final class XSLFPictureData extends POIXMLDocumentPart implements Picture
return PictureType.WDP; return PictureType.WDP;
} else if (XSLFRelation.IMAGE_TIFF.getContentType().equals(ct)) { } else if (XSLFRelation.IMAGE_TIFF.getContentType().equals(ct)) {
return PictureType.TIFF; return PictureType.TIFF;
} else if (XSLFRelation.IMAGE_SVG.getContentType().equals(ct)) {
return PictureType.SVG;
} else { } else {
return null; return null;
} }
@ -237,6 +239,7 @@ public final class XSLFPictureData extends POIXMLDocumentPart implements Picture
case WPG: return XSLFRelation.IMAGE_WPG; case WPG: return XSLFRelation.IMAGE_WPG;
case WDP: return XSLFRelation.IMAGE_WDP; case WDP: return XSLFRelation.IMAGE_WDP;
case TIFF: return XSLFRelation.IMAGE_TIFF; case TIFF: return XSLFRelation.IMAGE_TIFF;
case SVG: return XSLFRelation.IMAGE_SVG;
default: return null; default: return null;
} }
} }

View File

@ -19,18 +19,31 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
import java.awt.Dimension;
import java.awt.Insets; import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import javax.imageio.ImageIO;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
import org.apache.poi.xslf.draw.SVGImageRenderer;
import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
@ -55,6 +68,11 @@ public class XSLFPictureShape extends XSLFSimpleShape
implements PictureShape<XSLFShape,XSLFTextParagraph> { implements PictureShape<XSLFShape,XSLFTextParagraph> {
private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class); private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class);
private static final String DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
private static final String SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
private static final String BITMAP_URI = "{28A0092B-C50C-407E-A947-70E740481C1C}";
private static final String SVG_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
private XSLFPictureData _data; private XSLFPictureData _data;
/*package*/ XSLFPictureShape(CTPicture shape, XSLFSheet sheet) { /*package*/ XSLFPictureShape(CTPicture shape, XSLFSheet sheet) {
@ -196,6 +214,97 @@ public class XSLFPictureShape extends XSLFSimpleShape
return (r == null) ? null : new Insets(r.getT(), r.getL(), r.getB(), r.getR()); return (r == null) ? null : new Insets(r.getT(), r.getL(), r.getB(), r.getR());
} }
/**
* Add a SVG image reference
* @param svgPic a previously imported svg image
*/
public void setSvgImage(XSLFPictureData svgPic) {
CTBlip blip = getBlip();
CTOfficeArtExtensionList extLst = blip.isSetExtLst() ? blip.getExtLst() : blip.addNewExtLst();
final int bitmapId = getExt(extLst, BITMAP_URI);
CTOfficeArtExtension extBitmap;
if (bitmapId == -1) {
extBitmap = extLst.addNewExt();
extBitmap.setUri(BITMAP_URI);
XmlCursor cur = extBitmap.newCursor();
cur.toEndToken();
cur.beginElement(new QName(DML_NS, "useLocalDpi", "a14"));
cur.insertNamespace("a14", DML_NS);
cur.insertAttributeWithValue("val", "0");
cur.dispose();
}
final int svgId = getExt(extLst, SVG_URI);;
if (svgId != -1) {
extLst.removeExt(svgId);
}
String svgRelId = getSheet().getRelationId(svgPic);
if (svgRelId == null) {
svgRelId = getSheet().addRelation(null, XSLFRelation.IMAGE_SVG, svgPic).getRelationship().getId();
}
CTOfficeArtExtension svgBitmap = extLst.addNewExt();
svgBitmap.setUri(SVG_URI);
XmlCursor cur = svgBitmap.newCursor();
cur.toEndToken();
cur.beginElement(new QName(SVG_NS, "svgBlip", "asvg"));
cur.insertNamespace("asvg", SVG_NS);
cur.insertAttributeWithValue(new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel"), svgRelId);
cur.dispose();
}
/**
* Convienence method for adding SVG images, which generates the preview image
* @param sheet the sheet to add
* @param svgPic the svg picture to add
* @param previewType the preview picture type or null (defaults to PNG) - currently only JPEG,GIF,PNG are allowed
* @param anchor the image anchor (for calculating the preview image size) or
* null (the preview size is taken from the svg picture bounds)
*/
public static XSLFPictureShape addSvgImage(XSLFSheet sheet, XSLFPictureData svgPic, PictureType previewType, Rectangle2D anchor) throws IOException {
SVGImageRenderer renderer = new SVGImageRenderer();
try (InputStream is = svgPic.getInputStream()) {
renderer.loadImage(is, svgPic.getType().contentType);
}
Dimension dim = renderer.getDimension();
Rectangle2D anc = (anchor != null) ? anchor
: new Rectangle2D.Double(0,0, Units.pixelToPoints((int)dim.getWidth()), Units.pixelToPoints((int)dim.getHeight()));
PictureType pt = (previewType != null) ? previewType : PictureType.PNG;
if (pt != PictureType.JPEG || pt != PictureType.GIF || pt != PictureType.PNG) {
pt = PictureType.PNG;
}
BufferedImage thmBI = renderer.getImage(dim);
ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
// use extension instead of enum name, because of "jpeg"
ImageIO.write(thmBI, pt.extension.substring(1), bos);
XSLFPictureData pngPic = sheet.getSlideShow().addPicture(new ByteArrayInputStream(bos.toByteArray()), pt);
XSLFPictureShape shape = sheet.createPicture(pngPic);
shape.setAnchor(anc);
shape.setSvgImage(svgPic);
return shape;
}
private int getExt(CTOfficeArtExtensionList extLst, String uri) {
final int size = extLst.sizeOfExtArray();
for (int i=0; i<size; i++) {
CTOfficeArtExtension ext = extLst.getExtArray(i);
if (uri.equals(ext.getUri())) {
return i;
}
}
return -1;
}
@Override @Override
void copy(XSLFShape sh){ void copy(XSLFShape sh){
super.copy(sh); super.copy(sh);
@ -219,11 +328,11 @@ public class XSLFPictureShape extends XSLFSimpleShape
nvPr.unsetCustDataLst(); nvPr.unsetCustDataLst();
} }
if(blip.isSetExtLst()) { if(blip.isSetExtLst()) {
// TODO: check for SVG copying
CTOfficeArtExtensionList extLst = blip.getExtLst(); CTOfficeArtExtensionList extLst = blip.getExtLst();
//noinspection deprecation //noinspection deprecation
for(CTOfficeArtExtension ext : extLst.getExtArray()){ for(CTOfficeArtExtension ext : extLst.getExtArray()){
String xpath = "declare namespace a14='http://schemas.microsoft.com/office/drawing/2010/main' $this//a14:imgProps/a14:imgLayer"; String xpath = "declare namespace a14='"+ DML_NS +"' $this//a14:imgProps/a14:imgLayer";
XmlObject[] obj = ext.selectPath(xpath); XmlObject[] obj = ext.selectPath(xpath);
if(obj != null && obj.length == 1){ if(obj != null && obj.length == 1){
XmlCursor c = obj[0].newCursor(); XmlCursor c = obj[0].newCursor();
@ -234,6 +343,5 @@ public class XSLFPictureShape extends XSLFSimpleShape
} }
} }
} }
} }
} }

View File

@ -16,6 +16,8 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.IMAGE_PART;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -159,80 +161,87 @@ public final class XSLFRelation extends POIXMLRelation {
public static final XSLFRelation IMAGE_EMF = new XSLFRelation( public static final XSLFRelation IMAGE_EMF = new XSLFRelation(
PictureType.EMF.contentType, PictureType.EMF.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.emf", "/ppt/media/image#.emf",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_WMF = new XSLFRelation( public static final XSLFRelation IMAGE_WMF = new XSLFRelation(
PictureType.WMF.contentType, PictureType.WMF.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.wmf", "/ppt/media/image#.wmf",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_PICT = new XSLFRelation( public static final XSLFRelation IMAGE_PICT = new XSLFRelation(
PictureType.PICT.contentType, PictureType.PICT.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.pict", "/ppt/media/image#.pict",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_JPEG = new XSLFRelation( public static final XSLFRelation IMAGE_JPEG = new XSLFRelation(
PictureType.JPEG.contentType, PictureType.JPEG.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.jpeg", "/ppt/media/image#.jpeg",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_PNG = new XSLFRelation( public static final XSLFRelation IMAGE_PNG = new XSLFRelation(
PictureType.PNG.contentType, PictureType.PNG.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.png", "/ppt/media/image#.png",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_DIB = new XSLFRelation( public static final XSLFRelation IMAGE_DIB = new XSLFRelation(
PictureType.DIB.contentType, PictureType.DIB.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.dib", "/ppt/media/image#.dib",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_GIF = new XSLFRelation( public static final XSLFRelation IMAGE_GIF = new XSLFRelation(
PictureType.GIF.contentType, PictureType.GIF.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.gif", "/ppt/media/image#.gif",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_TIFF = new XSLFRelation( public static final XSLFRelation IMAGE_TIFF = new XSLFRelation(
PictureType.TIFF.contentType, PictureType.TIFF.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.tiff", "/ppt/media/image#.tiff",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_EPS = new XSLFRelation( public static final XSLFRelation IMAGE_EPS = new XSLFRelation(
PictureType.EPS.contentType, PictureType.EPS.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.eps", "/ppt/media/image#.eps",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_BMP = new XSLFRelation( public static final XSLFRelation IMAGE_BMP = new XSLFRelation(
PictureType.BMP.contentType, PictureType.BMP.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.bmp", "/ppt/media/image#.bmp",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_WPG = new XSLFRelation( public static final XSLFRelation IMAGE_WPG = new XSLFRelation(
PictureType.WPG.contentType, PictureType.WPG.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.wpg", "/ppt/media/image#.wpg",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_WDP = new XSLFRelation( public static final XSLFRelation IMAGE_WDP = new XSLFRelation(
PictureType.WDP.contentType, PictureType.WDP.contentType,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
"/ppt/media/image#.wdp", "/ppt/media/image#.wdp",
XSLFPictureData.class XSLFPictureData.class
); );
public static final XSLFRelation IMAGE_SVG = new XSLFRelation(
PictureType.SVG.contentType,
IMAGE_PART,
"/ppt/media/image#.svg",
XSLFPictureData.class
);
public static final XSLFRelation IMAGES = new XSLFRelation( public static final XSLFRelation IMAGES = new XSLFRelation(
null, null,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", IMAGE_PART,
null, null,
XSLFPictureData.class XSLFPictureData.class
); );

View File

@ -1,314 +0,0 @@
/* ====================================================================
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.
==================================================================== */
package org.apache.poi.poifs.crypt;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CRLException;
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.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
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.cert.ocsp.RevokedStatus;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
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.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class PkiTestUtils {
private PkiTestUtils() {
super();
}
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();
}
static X509Certificate generateCertificate(PublicKey subjectPublicKey,
String subjectDn, Date notBefore, Date notAfter,
X509Certificate issuerCertificate, PrivateKey issuerPrivateKey,
boolean caFlag, int pathLength, String crlUri, String ocspUri,
KeyUsage keyUsage)
throws IOException, OperatorCreationException, CertificateException
{
String signatureAlgorithm = "SHA1withRSA";
X500Name issuerName;
if (issuerCertificate != null) {
issuerName = new X509CertificateHolder(issuerCertificate.getEncoded()).getIssuer();
} else {
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 = (issuerCertificate != null)
? exUtils.createAuthorityKeyIdentifier(new X509CertificateHolder(issuerCertificate.getEncoded()))
: exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
if (caFlag) {
BasicConstraints bc;
if (-1 == pathLength) {
bc = new BasicConstraints(true);
} else {
bc = new BasicConstraints(pathLength);
}
certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
}
if (null != crlUri) {
int uri = GeneralName.uniformResourceIdentifier;
DERIA5String crlUriDer = new DERIA5String(crlUri);
GeneralName gn = new GeneralName(uri, crlUriDer);
DERSequence gnDer = new DERSequence(gn);
GeneralNames gns = GeneralNames.getInstance(gnDer);
DistributionPointName dpn = new DistributionPointName(0, gns);
DistributionPoint distp = new DistributionPoint(dpn, null, null);
DERSequence distpDer = new DERSequence(distp);
certificateGenerator.addExtension(Extension.cRLDistributionPoints, false, distpDer);
}
if (null != ocspUri) {
int uri = GeneralName.uniformResourceIdentifier;
GeneralName ocspName = new GeneralName(uri, ocspUri);
AuthorityInformationAccess authorityInformationAccess =
new AuthorityInformationAccess(X509ObjectIdentifiers.ocspAccessMethod, ocspName);
certificateGenerator.addExtension(Extension.authorityInfoAccess, false, authorityInformationAccess);
}
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);
}
static Document loadDocument(InputStream documentInputStream)
throws ParserConfigurationException, SAXException, IOException {
InputSource inputSource = new InputSource(documentInputStream);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
return documentBuilder.parse(inputSource);
}
static String toString(Node dom) throws TransformerException {
Source source = new DOMSource(dom);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
/*
* We have to omit the ?xml declaration if we want to embed the
* document.
*/
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
}
public 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);
}
public static OCSPResp createOcspResp(X509Certificate certificate,
boolean revoked, X509Certificate issuerCertificate,
X509Certificate ocspResponderCertificate,
PrivateKey ocspResponderPrivateKey, String signatureAlgorithm,
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;
if (revoked) {
certificateStatus = new RevokedStatus(new Date(), CRLReason.privilegeWithdrawn);
}
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);
}
}

View File

@ -29,6 +29,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -36,19 +37,30 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.math.BigInteger;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.Key; import java.security.Key;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.PrivateKey; 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.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509CRL; import java.security.cert.X509CRL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
@ -56,7 +68,9 @@ import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.dom.DOMSignContext;
import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo; import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
@ -90,8 +104,53 @@ import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.xmlbeans.SystemProperties; import org.apache.xmlbeans.SystemProperties;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
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.OCSPResp;
import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
import org.bouncycastle.cert.ocsp.Req;
import org.bouncycastle.cert.ocsp.RevokedStatus;
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.DigestAlgAndValueType;
import org.etsi.uri.x01903.v13.QualifyingPropertiesType; import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -408,7 +467,7 @@ public class TestSignatureInfo {
try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) { try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {
initKeyPair("Test", "CN=Test"); initKeyPair("Test", "CN=Test");
final X509CRL crl = PkiTestUtils.generateCrl(x509, keyPair.getPrivate()); final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
// setup // setup
SignatureConfig signatureConfig = new SignatureConfig(); SignatureConfig signatureConfig = new SignatureConfig();
@ -481,7 +540,7 @@ public class TestSignatureInfo {
final RevocationData revocationData = new RevocationData(); final RevocationData revocationData = new RevocationData();
revocationData.addCRL(crl); revocationData.addCRL(crl);
OCSPResp ocspResp = PkiTestUtils.createOcspResp(x509, false, OCSPResp ocspResp = createOcspResp(x509, false,
x509, x509, keyPair.getPrivate(), "SHA1withRSA", cal.getTimeInMillis()); x509, x509, keyPair.getPrivate(), "SHA1withRSA", cal.getTimeInMillis());
revocationData.addOCSP(ocspResp.getEncoded()); revocationData.addOCSP(ocspResp.getEncoded());
@ -721,18 +780,84 @@ public class TestSignatureInfo {
@Test @Test
public void testMultiSign() throws Exception { public void testMultiSign() throws Exception {
initKeyPair("KeyA", "CN=KeyA"); cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
//KeyPair keyPairA = keyPair; cal.clear();
//X509Certificate x509A = x509; cal.setTimeZone(LocaleUtil.TIMEZONE_UTC);
initKeyPair("KeyB", "CN=KeyB"); cal.set(2018, Calendar.DECEMBER, 14);
//KeyPair keyPairB = keyPair;
//X509Certificate x509B = x509;
File tpl = copy(testdata.getFile("bug58630.xlsx")); // test signing with separate opened packages
File tpl = copy(testdata.getFile("hello-world-unsigned.xlsx"));
try (OPCPackage pkg = OPCPackage.open(tpl)) { try (OPCPackage pkg = OPCPackage.open(tpl)) {
//SignatureConfig signatureConfig = new SignatureConfig(); signPkg63011(pkg, "bug63011_key1.pem", true);
assertNotNull(pkg);
} }
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();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
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);
config.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(config);
si.confirmSignature();
} }
@Test @Test
@ -829,14 +954,14 @@ public class TestSignatureInfo {
x509 = (X509Certificate)keystore.getCertificate(alias); x509 = (X509Certificate)keystore.getCertificate(alias);
keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key); keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
} else { } else {
keyPair = PkiTestUtils.generateKeyPair(); keyPair = generateKeyPair();
Date notBefore = cal.getTime(); Date notBefore = cal.getTime();
Calendar cal2 = (Calendar)cal.clone(); Calendar cal2 = (Calendar)cal.clone();
cal2.add(Calendar.YEAR, 1); cal2.add(Calendar.YEAR, 1);
Date notAfter = cal2.getTime(); Date notAfter = cal2.getTime();
KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature); KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature);
x509 = PkiTestUtils.generateCertificate(keyPair.getPublic(), subjectDN x509 = generateCertificate(keyPair.getPublic(), subjectDN
, notBefore, notAfter, null, keyPair.getPrivate(), true, 0, null, null, keyUsage); , notBefore, notAfter, null, keyPair.getPrivate(), true, 0, null, null, keyUsage);
keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509}); keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
@ -849,6 +974,27 @@ public class TestSignatureInfo {
} }
} }
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 { private static File copy(File input) throws IOException {
String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1"); String extension = input.getName().replaceAll(".*?(\\.[^.]+)?$", "$1");
if (extension == null || extension.isEmpty()) { if (extension == null || extension.isEmpty()) {
@ -872,4 +1018,187 @@ public class TestSignatureInfo {
return tmpFile; 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,
String subjectDn, Date notBefore, Date notAfter,
X509Certificate issuerCertificate, PrivateKey issuerPrivateKey,
boolean caFlag, int pathLength, String crlUri, String ocspUri,
KeyUsage keyUsage)
throws IOException, OperatorCreationException, CertificateException
{
String signatureAlgorithm = "SHA1withRSA";
X500Name issuerName;
if (issuerCertificate != null) {
issuerName = new X509CertificateHolder(issuerCertificate.getEncoded()).getIssuer();
} else {
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 = (issuerCertificate != null)
? exUtils.createAuthorityKeyIdentifier(new X509CertificateHolder(issuerCertificate.getEncoded()))
: exUtils.createAuthorityKeyIdentifier(subjectPublicKeyInfo);
certificateGenerator.addExtension(Extension.subjectKeyIdentifier, false, subKeyId);
certificateGenerator.addExtension(Extension.authorityKeyIdentifier, false, autKeyId);
if (caFlag) {
BasicConstraints bc;
if (-1 == pathLength) {
bc = new BasicConstraints(true);
} else {
bc = new BasicConstraints(pathLength);
}
certificateGenerator.addExtension(Extension.basicConstraints, false, bc);
}
if (null != crlUri) {
int uri = GeneralName.uniformResourceIdentifier;
DERIA5String crlUriDer = new DERIA5String(crlUri);
GeneralName gn = new GeneralName(uri, crlUriDer);
DERSequence gnDer = new DERSequence(gn);
GeneralNames gns = GeneralNames.getInstance(gnDer);
DistributionPointName dpn = new DistributionPointName(0, gns);
DistributionPoint distp = new DistributionPoint(dpn, null, null);
DERSequence distpDer = new DERSequence(distp);
certificateGenerator.addExtension(Extension.cRLDistributionPoints, false, distpDer);
}
if (null != ocspUri) {
int uri = GeneralName.uniformResourceIdentifier;
GeneralName ocspName = new GeneralName(uri, ocspUri);
AuthorityInformationAccess authorityInformationAccess =
new AuthorityInformationAccess(X509ObjectIdentifiers.ocspAccessMethod, ocspName);
certificateGenerator.addExtension(Extension.authorityInfoAccess, false, authorityInformationAccess);
}
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,
boolean revoked, X509Certificate issuerCertificate,
X509Certificate ocspResponderCertificate,
PrivateKey ocspResponderPrivateKey, String signatureAlgorithm,
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;
if (revoked) {
certificateStatus = new RevokedStatus(new Date(), CRLReason.privilegeWithdrawn);
}
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);
}
} }

View File

@ -16,14 +16,17 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.POIDataSamples.TEST_PROPERTY;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
@ -247,4 +250,24 @@ public class TestXSLFPictureShape {
slideShow.close(); slideShow.close();
} }
@Test
public void renderSvgImage() throws Exception {
String dataDirName = System.getProperty(TEST_PROPERTY);
final String SVG_FILE = (dataDirName != null ? "../" : "") + "src/documentation/resources/images/project-header.svg";
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFPictureData svgPic = ppt.addPicture(new File(dataDirName, SVG_FILE), PictureType.SVG);
XSLFPictureShape shape = XSLFPictureShape.addSvgImage(slide, svgPic, PictureType.JPEG, null);
Rectangle2D anchor = shape.getAnchor();
anchor.setRect(100, 100, anchor.getWidth(), anchor.getHeight());
shape.setAnchor(anchor);
// try (FileOutputStream fos = new FileOutputStream("svgtest.pptx")) {
// ppt.write(fos);
// }
}
} }

View File

@ -0,0 +1,45 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCr+sR6OR6R49ni
/w/jjCSOewGvOjzJelKaGoT/cYmvx6JFrFwy3PV7FZEhRPQCKvE+cCOYAwBFTC7K
uN0h/cen7tVF/idVWlzOTU/3Tdy/J7sb2KfToHvjxKkeMUl1SHvf1et+3HQHQSII
Vf8A3cu0cL91sYSd32ZZYm2TeKxbTc1GO/R9OzvSOxCQaIVbAiMQvY04EQZb0F7/
eBRj8UAdMbsTRVYuOSWrXX2DL5U3/nq/c8F0ozeyUOEbzWacZ83OcDEFC0hCrGyy
ptKtEQBWhbgSZ9BRc5nZ9q97VoDOLwrb24zBI45AsRBvwRAhf5DLV5cOw6X8MdQd
p0pKcN9HAgMBAAECggEAVcPyNe3EZAcYQw7mMplSJcgMOAG4DNY22Wk+SFGr04Cg
WVSyih8NQPupa8kCUw5tTrEH3ygn+2cZsrlsdiYkaog9zfEIVpWA0NVXesJWwvGi
aymp0G0pO5Z4rHjx5E5okGETVynDp1aBDV0tlZYGn47WvG/x7fVaClt+v9ufQMyD
snUEf2lpWhUtoUhlOnDZr791QPLUkVi0roLSD0M2vPM1cbV8EO4SdhOOyTDCNFvo
IAcysKV0UBN/TJOyB7FyDw1cJtJ9Ja/X9YoLcW+0fTZNhlYq6VrowCQyEchlb8Pz
bRhUJc6oGffpaxtrMk8pmTSScpSTV5PtB3E4t6mYYQKBgQDVPX+GdnuNyyNdvF3g
SplJZdyAjW21mZ4gdYLxyGHIsgTrz4SKJ49HZoaDdwwpQRZWnQC7gxCXbJ2IHwMF
+Qz7pp7eoRhQ3eBqQxfIypOeRSC6n3OIOYxIJlcV3O/PTGwu2eJhxck1ZG/j90DW
NDo9hQYLFpD2xGiaWd611HncsQKBgQDOdzBZF/1PbUh/zz1nwAVPT85IM1vwU85k
LIQUY/P+LFUvSa7gk3sabn6Zop5Cv0z+I1j5NW1lobLR4u02jqIb/dqeJ+XOt27n
UMiYI/6WBA6Mkrf9j10BpFuSBWYotpkr8PZcog1v+FnODcOsG6Nl7fiJjkpPD6AF
MCIHip4ZdwKBgC4fKhkMQXcOy+x3VJqxp+v/My0+6c7QlioRIKxpGfVNw9C5RsKX
Ad+ApnGC60d1A37iYIkuNQV7gasygfXlw1Ae3tfqYhcDlomFT3ynjDw8WXLkEBoT
0Gq+mDFrYxckQXX0vIlHPVjmC2l0TjrGex5ZSlBVpi8pljJkY85SUbVRAoGBAICq
BCYxbfl2aAzGEEU8g9KWMD4MS4osH92LZE/0rhPCet96MpHfNoMVQq3pimicIJXr
X0IGSoNgTjjACwXJwzpga0HOKUc2RtW+IRO2squ4IXz23dQU6GfijfIkjTJoAHJC
urSlhGw3v3dKWptBqgUWVKEcXDCC0z0Ibtx2ROonAoGAWcRq3xpkbeR4K4yd+K9w
4CBi8sdlz48tmZDSVigjq27Jk/6Ttk5K6x8M1rhUWYZ+ak1Y2NVV24oqnIdtIZrE
BdgvzJCJN3Yx3FMYzUVqONFfGyppi0E7WvSYX0qlXKeZDcjgp1ORCOhiQL3ufE1+
LdXLunLfjJzNnvX7XoTAyyE=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICojCCAYqgAwIBAgIEXA5r3jANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhN
dWogS2xpYzAeFw0xODEyMTAxMzM2MzBaFw0xOTEyMTAxMzM2MzBaMBMxETAPBgNV
BAMMCE11aiBLbGljMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq/rE
ejkekePZ4v8P44wkjnsBrzo8yXpSmhqE/3GJr8eiRaxcMtz1exWRIUT0AirxPnAj
mAMARUwuyrjdIf3Hp+7VRf4nVVpczk1P903cvye7G9in06B748SpHjFJdUh739Xr
ftx0B0EiCFX/AN3LtHC/dbGEnd9mWWJtk3isW03NRjv0fTs70jsQkGiFWwIjEL2N
OBEGW9Be/3gUY/FAHTG7E0VWLjklq119gy+VN/56v3PBdKM3slDhG81mnGfNznAx
BQtIQqxssqbSrREAVoW4EmfQUXOZ2fave1aAzi8K29uMwSOOQLEQb8EQIX+Qy1eX
DsOl/DHUHadKSnDfRwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAJ5hi+ZinJ4QOA
hC2sPuawdj6k+C3+CXNpRV5eMagBJZYPMsUfEPrP7ZjRiBpQVQyx6rktXqObrmTw
e12yMor5cc8kGyQ6GmYoEoCKFS/S08fK5j5bwwy8KWfyH8tRGsEHeowPw3eIZCv7
gowUhb3SOsh3osAtafSe9aS0rGNTGBdSTFnJEiew8zpWbdIFKySYxU8nmHNpIPXh
O/EuAYMwbcF3BhM20Gm5hxqrgSWe7S+q3KqSJbs+k95j0jr8xoNzwUd8NzI40Uu1
L1ejyqvGHjxhQooIej1Ea/MSp7v5ifpBWSp3yxlOjAnZPSEewCutMyHylIulS0sK
2JQfgcdd
-----END CERTIFICATE-----

View File

@ -0,0 +1,45 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMcC/+xW5l/R8i
M9IKNdebiCQxkn/gfSjXD7oddrg42POCuPElhaGlHXPI+DCvNQ1+lbCTDJ7rk8F2
DbefV80uwzMkMKnn0i3GW2K8LIGrv74ACYIzueHK+Mrm3N90/Xb6IqSR430SYH9r
RbIfCqCVa0LJbVS2Pw2vBmvJHE/DVoSjKXlO73EbN4G4lJnj80NaZp6I0DDsoVup
htKJWLtYwB3CDpI0oDst8/Beq7esDyyHHWf3v0TOtH19lRWSoD9yEmg+bRMKYfnu
T5rWj8tF+cRjh+SIyBjuIn7n4qwnAs62CQKFLjp/3PjOEbaD/aCX+6xMWvAtk0UT
KIDwYsejAgMBAAECggEAX0h2hibconpMFXPTlGCt4dadD+G46hdLfpjc5Lidehlb
vXSXKCbVRRCqE2PhxPdUF8iKqK68Lw4JoA0apRCWGBJwdpCbz+k83nNfXFbeBP9z
/a5w2czr+N7mKp2NJIix+DlHPJurgnIpUQUF1MPuPlXkpd7oGZzfstCqUex5HJAU
N03lL/Z5/hgq93sLh1ZgPWhwAOYnps0rsOnFYXlXW7WVXvL1xpyBidZstOw+BdVC
7BQNvKVa4KGC/PdgW7K4327JeMjRsX1nDUzZbORM5wihLE5idIHmDbQUm4G8JZul
tLeV2Ew28L91jcc55Pbe40tBeMSqgSuU2r6/dU4uCQKBgQDlUCI8vW1Q7J92m+zU
Y8lHu5mS4nlwXJEpuUoCuD2falAZW40+sG3fqZ1tEiCEpEYSYKMP0vbFrNLQ68av
HWhjXWCQFvuUfAK8BsMusRIBQ/ZJduSa5vSgsQA+ZVl/Pnj9PyMN70nhueHcXjnM
SNo5X3BQMNERaec7Lr0mRjDGHwKBgQDkOvcbdt4gCwpAeARzCTh15uw+q8KWPz77
hPbaO4GJIMZZmRULhsrgBNZAsREasO4ZKJLI+wtukCXqgHAGzdSl6aK1fDLgFYqP
Hp8UvgvIdF5yV7oAma9gRbK47sQlyBSFvQUyAuvA7wcviQ43/TIa173iBS07WfpA
KlZu6+Ol/QKBgQDMJfglDRtKJS6eIJjKSQADzZ8eZmNoxfAyLhQWscGir7oZqSjo
+5cFvPI7DR1IGRuM9t2Uk+M//uk8N/uNIOgzNglmnh9hhLnGfVq8scVuvPuBUciZ
oy179bha1E3F+28pPlFN8Y9b1umeD4DzPpSQ6UeLDLrD/v1t8eFRNsHrTwKBgE7v
4gW6wCrfBqWznP5YoxGMVAt9BqlGqLb/jw195ViTYGce3juFXGfM5HmthFfx9/f1
o4cl5RdRffu0foqr6C+WNjOFCGeeq7TCh4z6CkNDlGMB2pBYl2K52I3D702N/SMg
dEqO3hF12stjIOrWhNzp33/sAG/1t+s3eXuV1L/VAoGAe0d/g5LcACFbl0sDRcSV
WYsKHyR2dieALKf47mhzQtKmY506zM22n52s9sUT92j4jf/4dnP5OciJniSppgfW
V64/856DuMNPoIssmNh3tQwjm8I0/t+iDGJJSHnQthG0AwD2NRe/D8Uty4P7ED64
0gEVrDJEgT60MrQt15f+1sM=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICrDCCAZSgAwIBAgIEXA/YwjANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1N
eSBTZWNvbmQga2V5MB4XDTE4MTIxMTE1MzMyMloXDTE5MTIxMTE1MzMyMlowGDEW
MBQGA1UEAwwNTXkgU2Vjb25kIGtleTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMxwL/7FbmX9HyIz0go115uIJDGSf+B9KNcPuh12uDjY84K48SWFoaUd
c8j4MK81DX6VsJMMnuuTwXYNt59XzS7DMyQwqefSLcZbYrwsgau/vgAJgjO54cr4
yubc33T9dvoipJHjfRJgf2tFsh8KoJVrQsltVLY/Da8Ga8kcT8NWhKMpeU7vcRs3
gbiUmePzQ1pmnojQMOyhW6mG0olYu1jAHcIOkjSgOy3z8F6rt6wPLIcdZ/e/RM60
fX2VFZKgP3ISaD5tEwph+e5PmtaPy0X5xGOH5IjIGO4ifufirCcCzrYJAoUuOn/c
+M4RtoP9oJf7rExa8C2TRRMogPBix6MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
n3rvm1DatfrrFdhNOfNwlYMF12ND1BIEFYYI13vIkZ5wmb+gNYZu32FqdTpX//qV
VkNLXJj/DrR+rKWH2jZwabaYyv5XmJl9Y0/LqN3ExiqijYsPgpWEKCzhfyv+Qe5B
Qzx8WCJjGh0UMQ3P8/FRYsUPf5AFMdz9jZK0uYCFFgkb4LDp23MbNYG4eRBB+/+R
Arq/poWd+eb5G79+rnrGGCtqhVuxrMP8xkPy4Rkg8zr56CxQSHX7qXehYc9x/dTj
CyHPrOUAw4W/pYShYtHsqORQivPvwnwQQ4upK6s2l5pbPwyEzV45clIPU+3tjvn7
67DLhc66Sz4/XkWeEXeeMg==
-----END CERTIFICATE-----