Skip to content
Commits on Source (4)
Release Notes -- Apache PDFBox -- Version 2.0.11
Release Notes -- Apache PDFBox -- Version 2.0.12
Introduction
------------
The Apache PDFBox library is an open source Java tool for working with PDF documents.
This is an incremental bugfix release based on the earlier 2.0.10 release. It contains
This is an incremental bugfix release based on the earlier 2.0.11 release. It contains
a couple of fixes and small improvements.
For more details on these changes and all the other fixes and improvements
......@@ -14,11 +14,52 @@ PDFBox issue tracker at https://issues.apache.org/jira/browse/PDFBOX.
Bug
[PDFBOX-4248] - NPE when rendering a PDF with annotations using a g2d from Batik
[PDFBOX-4013] - Java 9/macOS: Debugger App does not start (NoSuchMethodException)
[PDFBOX-4219] - Multithreading problem when rendering several documents with Standard 14 fonts
[PDFBOX-4242] - Fontbox does not close file descriptor when loading fonts.
[PDFBOX-4245] - wrong rendering of the transparency group at the specific position on a page
[PDFBOX-4254] - PDDocument.close() might ignore throwing an Exception
[PDFBOX-4266] - Java 6 error
[PDFBOX-4267] - Incorrect rendering when /Matte entry
[PDFBOX-4268] - Japanese text displayed as barcode
[PDFBOX-4276] - Multiply blend mode not detected
[PDFBOX-4278] - Type 3 font .notdef-named glyph missing in rendering
[PDFBOX-4279] - ArrayIndexOutOfBoundsException in PDDeviceGray.toRGB
[PDFBOX-4283] - Allowing Rectangles with additional elements
[PDFBOX-4288] - needless adding while parsing dictionary objects
[PDFBOX-4291] - JavaDoc on website is marked as being in German
[PDFBOX-4292] - Validation fails if ModifyDate and ModDate are specified using different time zones
[PDFBOX-4298] - NullPointerException when doing overlay
[PDFBOX-4299] - ArrayIndexOutOfBoundsException in CmapSubtable.processSubtype2
[PDFBOX-4301] - ClassCastException in PDExtendedGraphicsState
[PDFBOX-4302] - ToUnicode CMap is not written correctly when the entry count is just 100.
[PDFBOX-4305] - Log message not in english
[PDFBOX-4306] - Image clipping area rounding error
[PDFBOX-4307] - ClassCastException in PDDocumentCatalog.getDocumentOutline if 'outlines' is not a dictionary
[PDFBOX-4308] - PDDocument protect changes color palette
[PDFBOX-4315] - PDFBox info message when not using it
[PDFBOX-4316] - RemoveAllText does not delete all parameters with " operator
[PDFBOX-4318] - PDFont.encode results change on identical input
[PDFBOX-4319] - Parsing 100000 page pdf is slow
[PDFBOX-4322] - Extract Text feature is not working for some part of PDF
Improvement
[PDFBOX-4251] - Optimize AFMParser
[PDFBOX-4184] - [PATCH]: Support simple lossless compression of 16 bit RGB images
[PDFBOX-4253] - Optimize PDFunctionType3.eval()
[PDFBOX-4256] - Return default value for CheckBox / RadioButton if /V entry is missing (widget /AS entries are present)
[PDFBOX-4259] - Add polygon annotation to AddAnnotations.java example
[PDFBOX-4260] - Reduce RAM requirement of COSOutputStream
[PDFBOX-4263] - Check object key when signing
[PDFBOX-4271] - Consistently using the same version of the download-maven-plugin
[PDFBOX-4274] - Get rid of warning about prerequisites
[PDFBOX-4285] - Expose the tiff compression type to the user.
[PDFBOX-4289] - Double negative number
[PDFBOX-4295] - Don't create intermediate streams when merging files
Task
[PDFBOX-4281] - Replace Apache Wink dependency
Release Contents
----------------
......@@ -30,7 +71,7 @@ See the README.txt file for instructions on how to build this release.
The source archive is accompanied by a SHA512 checksum and a PGP signature
that you can use to verify the authenticity of your download.
The public key used for the PGP signature can be found at
https://svn.apache.org/repos/asf/pdfbox/KEYS.
https://www.apache.org/dist/pdfbox/KEYS.
About Apache PDFBox
-------------------
......
......@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-parent</artifactId>
<version>2.0.11</version>
<version>2.0.12</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
......
libpdfbox2-java (2.0.12-1) unstable; urgency=medium
* New upstream version 2.0.12.
- Fix CVE-2018-11797: denial-of-service via specially crafted PDF file.
(Closes: #910391)
* Declare compliance with Debian Policy 4.2.1.
-- Markus Koschany <apo@debian.org> Sat, 06 Oct 2018 12:05:00 +0200
libpdfbox2-java (2.0.11-1) unstable; urgency=medium
* New upstream version 2.0.11.
......
......@@ -18,7 +18,7 @@ Build-Depends:
libmaven-javadoc-plugin-java,
libpdfbox2-java,
maven-debian-helper
Standards-Version: 4.1.4
Standards-Version: 4.2.1
Vcs-Git: https://anonscm.debian.org/git/pkg-java/libpdfbox2-java.git
Vcs-Browser: https://anonscm.debian.org/git/pkg-java/libpdfbox2-java.git
Homepage: http://pdfbox.apache.org
......
......@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-parent</artifactId>
<version>2.0.11</version>
<version>2.0.12</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
......
......@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-parent</artifactId>
<version>2.0.11</version>
<version>2.0.12</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
......
......@@ -43,7 +43,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.imageio.spi.IIORegistry;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
......@@ -302,10 +301,20 @@ public class PDFDebugger extends JFrame
}
});
initGlobalEventHandlers();
}
/**
* Initialize application global event handlers. Protected to allow
* subclasses to override this method if they don't want the global event
* handler overridden.
*/
@SuppressWarnings("WeakerAccess")
protected void initGlobalEventHandlers()
{
// Mac OS X file open/quit handler
if (IS_MAC_OS && !isMinJdk9())
if (IS_MAC_OS)
{
//TODO this needs to be rewritten for JDK9, see PDFBOX-4013
try
{
Method osxOpenFiles = getClass().getDeclaredMethod("osxOpenFiles", String.class);
......@@ -417,11 +426,8 @@ public class PDFDebugger extends JFrame
}
});
if (!IS_MAC_OS)
{
fileMenu.addSeparator();
fileMenu.add(printMenuItem);
}
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.setAccelerator(KeyStroke.getKeyStroke("alt F4"));
......@@ -632,7 +638,7 @@ public class PDFDebugger extends JFrame
openDialog.setVisible(true);
if (openDialog.getFile() != null)
{
readPDFFile(openDialog.getFile(), "");
readPDFFile(new File(openDialog.getDirectory(),openDialog.getFile()), "");
}
}
else
......@@ -1077,7 +1083,7 @@ public class PDFDebugger extends JFrame
return data;
}
private void exitMenuItemActionPerformed(ActionEvent evt)
private void exitMenuItemActionPerformed(ActionEvent ignored)
{
if( document != null )
{
......@@ -1095,6 +1101,16 @@ public class PDFDebugger extends JFrame
throw new RuntimeException(e);
}
}
performApplicationExit();
}
/**
* Exit the application after the window is closed. This is protected to let
* subclasses override the behavior.
*/
@SuppressWarnings("WeakerAccess")
protected void performApplicationExit()
{
System.exit(0);
}
......@@ -1151,23 +1167,7 @@ public class PDFDebugger extends JFrame
*/
private void exitForm(WindowEvent evt)
{
if( document != null )
{
try
{
document.close();
if (!currentFilePath.startsWith("http"))
{
recentFiles.addFile(currentFilePath);
}
recentFiles.close();
}
catch( IOException e )
{
throw new RuntimeException(e);
}
}
System.exit(0);
exitMenuItemActionPerformed(null);
}
/**
......@@ -1495,26 +1495,4 @@ public class PDFDebugger extends JFrame
}
return null;
}
private static boolean isMinJdk9()
{
// strategy from lucene-solr/lucene/core/src/java/org/apache/lucene/util/Constants.java
String version = System.getProperty("java.specification.version");
final StringTokenizer st = new StringTokenizer(version, ".");
try
{
int major = Integer.parseInt(st.nextToken());
int minor = 0;
if (st.hasMoreTokens())
{
minor = Integer.parseInt(st.nextToken());
}
return major > 1 || (major == 1 && minor >= 9);
}
catch (NumberFormatException nfe)
{
// maybe some new numbering scheme in the 22nd century
return true;
}
}
}
......@@ -90,7 +90,7 @@ public class CSSeparation implements ChangeListener, ActionListener
slider.setMajorTickSpacing(50);
slider.setPaintTicks(true);
Dictionary labelTable = new Hashtable();
Dictionary<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
JLabel lightest = new JLabel("lightest");
lightest.setFont(new Font(Font.MONOSPACED, Font.BOLD, 10));
JLabel darkest = new JLabel("darkest");
......
......@@ -43,7 +43,7 @@ import javax.swing.border.LineBorder;
/**
* @author Khyrul Bashar
*
* This class hosts all the UI components of Hex view and cordinate among them.
* This class hosts all the UI components of Hex view and coordinates among them.
*/
class HexEditor extends JPanel implements SelectionChangeListener
{
......
......@@ -23,7 +23,7 @@ import java.util.List;
/**
* @author Khyrul Bashar
*
* A class that acts as a model for the hex viewer. It holds the data and provide the data as ncessary.
* A class that acts as a model for the hex viewer. It holds the data and provide the data as necessary.
* It'll let listen for any underlying data changes.
*/
class HexModel implements HexChangeListener
......
......@@ -26,11 +26,10 @@ import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JComponent;
......@@ -146,8 +145,15 @@ public class StreamPane implements ActionListener
}
tabbedPane = new JTabbedPane();
if (stream.isImage())
{
tabbedPane.add("Image view", view.getStreamPanel());
}
else
{
tabbedPane.add("Text view", view.getStreamPanel());
tabbedPane.add("Hex view", hexView.getPane());
}
panel.add(tabbedPane);
}
......@@ -159,7 +165,7 @@ public class StreamPane implements ActionListener
private JPanel createHeaderPanel(List<String> availableFilters, String i, ActionListener actionListener)
{
JComboBox filters = new JComboBox(availableFilters.toArray());
JComboBox<String> filters = new JComboBox<String>(new Vector<String>(availableFilters));
filters.setSelectedItem(i);
filters.addActionListener(actionListener);
......@@ -182,8 +188,13 @@ public class StreamPane implements ActionListener
if (currentFilter.equals(Stream.IMAGE))
{
requestImageShowing();
tabbedPane.removeAll();
tabbedPane.add("Image view", view.getStreamPanel());
return;
}
tabbedPane.removeAll();
tabbedPane.add("Text view", view.getStreamPanel());
tabbedPane.add("Hex view", hexView.getPane());
requestStreamText(currentFilter);
}
catch (IOException e)
......@@ -208,13 +219,6 @@ public class StreamPane implements ActionListener
return;
}
view.showStreamImage(image);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", baos);
baos.flush();
byte[] bytes = baos.toByteArray();
baos.close();
hexView.changeData(bytes);
}
}
......
......@@ -64,10 +64,14 @@
package org.apache.pdfbox.debugger.ui;
import java.awt.Desktop;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.StringTokenizer;
import java.util.List;
/**
* Hooks existing preferences/about/quit functionality from an
......@@ -88,9 +92,62 @@ public class OSXAdapter implements InvocationHandler
static Object macOSXApplication;
private static boolean isMinJdk9()
{
// strategy from lucene-solr/lucene/core/src/java/org/apache/lucene/util/Constants.java
String version = System.getProperty("java.specification.version");
final StringTokenizer st = new StringTokenizer(version, ".");
try
{
int major = Integer.parseInt(st.nextToken());
int minor = 0;
if (st.hasMoreTokens())
{
minor = Integer.parseInt(st.nextToken());
}
return major > 1 || (major == 1 && minor >= 9);
}
catch (NumberFormatException nfe)
{
// maybe some new numbering scheme in the 22nd century
return true;
}
}
// Pass this method an Object and Method equipped to perform application shutdown logic
// The method passed should return a boolean stating whether or not the quit should occur
public static void setQuitHandler(Object target, Method quitHandler) {
public static void setQuitHandler(final Object target, final Method quitHandler)
{
if (isMinJdk9())
{
try
{
Desktop desktopObject = Desktop.getDesktop();
Class<?> filesHandlerClass = Class.forName("java.awt.desktop.QuitHandler");
final Method setQuitHandlerMethod = desktopObject.getClass().getMethod("setQuitHandler", filesHandlerClass);
Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(),
new Class[] { filesHandlerClass }, new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
if ("handleQuitRequestWith".equals(method.getName()))
{
// We just call our own quit handler
quitHandler.invoke(target);
}
return null;
}
});
setQuitHandlerMethod.invoke(desktopObject, osxAdapterProxy);
}
catch (Exception e)
{
e.printStackTrace();
}
return;
}
setHandler(new OSXAdapter("handleQuit", target, quitHandler));
}
......@@ -133,10 +190,59 @@ public class OSXAdapter implements InvocationHandler
// Pass this method an Object and a Method equipped to handle document events from the Finder
// Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
// application bundle's Info.plist
public static void setFileHandler(Object target, Method fileHandler) {
setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
public static void setFileHandler(Object target, Method fileHandler)
{
if (isMinJdk9())
{
try
{
Desktop desktopObject = Desktop.getDesktop();
Class<?> filesHandlerClass = Class.forName("java.awt.desktop.OpenFilesHandler");
Method setOpenFileHandlerMethod = desktopObject.getClass().getMethod("setOpenFileHandler", filesHandlerClass);
Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(),
new Class[]
{
filesHandlerClass
}, new OSXAdapter("openFiles", target, fileHandler)
{
// Override OSXAdapter.callTarget to send information on the
// file to be opened
@Override
public boolean callTarget(Object openFilesEvent)
{
if (openFilesEvent != null)
{
try
{
Method getFilesMethod = openFilesEvent.getClass().getDeclaredMethod("getFiles",
(Class[]) null);
@SuppressWarnings("unchecked")
List<File> files = (List<File>) getFilesMethod.invoke(openFilesEvent,
(Object[]) null);
this.targetMethod.invoke(this.targetObject, files.get(0).getAbsolutePath());
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
return true;
}
});
setOpenFileHandlerMethod.invoke(desktopObject, osxAdapterProxy);
}
catch (Exception e)
{
e.printStackTrace();
}
return;
}
/* JDK <= 1.8, using Apple classes */
setHandler(new OSXAdapter("handleOpenFile", target, fileHandler)
{
// Override OSXAdapter.callTarget to send information on the
// file to be opened
@Override
public boolean callTarget(Object appleEvent) {
if (appleEvent != null) {
try {
......
......@@ -18,6 +18,7 @@
package org.apache.pdfbox.debugger.ui;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
......@@ -63,12 +64,18 @@ public class PageEntry
COSDictionary node = dict;
while (node.containsKey(COSName.PARENT))
{
COSDictionary parent = (COSDictionary)node.getDictionaryObject(COSName.PARENT);
COSArray kids = (COSArray)parent.getDictionaryObject(COSName.KIDS);
if (kids == null)
COSBase base = node.getDictionaryObject(COSName.PARENT);
if (!(base instanceof COSDictionary))
{
return "";
}
COSDictionary parent = (COSDictionary) base;
base = parent.getDictionaryObject(COSName.KIDS);
if (!(base instanceof COSArray))
{
return "";
}
COSArray kids = (COSArray) base;
int idx = kids.indexOfObject(node);
sb.append("/Kids/[").append(idx).append("]");
node = parent;
......
......@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-parent</artifactId>
<version>2.0.11</version>
<version>2.0.12</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
......@@ -77,7 +77,7 @@
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.6</version>
<version>1.10.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
......@@ -85,9 +85,15 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.wink</groupId>
<artifactId>wink-component-test-support</artifactId>
<version>1.4</version>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jaxrs_1.1_spec</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
......
......@@ -18,6 +18,9 @@ package org.apache.pdfbox.examples.pdmodel;
import java.io.IOException;
import java.util.List;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
......@@ -31,6 +34,7 @@ import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLine;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationMarkup;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationSquareCircle;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;
......@@ -70,6 +74,7 @@ public final class AddAnnotations
// Some basic reusable objects/constants
// Annotations themselves can only be used once!
PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
PDColor green = new PDColor(new float[] { 0, 1, 0 }, PDDeviceRGB.INSTANCE);
PDColor blue = new PDColor(new float[] { 0, 0, 1 }, PDDeviceRGB.INSTANCE);
PDColor black = new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE);
......@@ -237,6 +242,28 @@ public final class AddAnnotations
pageLink.setAction(actionGoto);
annotations.add(pageLink);
// create a polygon annotation. Yes this is clunky, it will be easier in 3.0
PDAnnotationMarkup polygon = new PDAnnotationMarkup();
polygon.getCOSObject().setName(COSName.SUBTYPE, PDAnnotationMarkup.SUB_TYPE_POLYGON);
position = new PDRectangle();
position.setLowerLeftX(pw - INCH);
position.setLowerLeftY(ph - INCH);
position.setUpperRightX(pw - 2 * INCH);
position.setUpperRightY(ph - 2 * INCH);
polygon.setRectangle(position);
polygon.setColor(blue); // border color
polygon.getCOSObject().setItem(COSName.IC, green.toCOSArray()); // interior color
COSArray verticesArray = new COSArray();
verticesArray.add(new COSFloat(pw - INCH));
verticesArray.add(new COSFloat(ph - 2 * INCH));
verticesArray.add(new COSFloat(pw - INCH * 1.5f));
verticesArray.add(new COSFloat(ph - INCH));
verticesArray.add(new COSFloat(pw - 2 * INCH));
verticesArray.add(new COSFloat(ph - 2 * INCH));
polygon.getCOSObject().setItem(COSName.VERTICES, verticesArray);
polygon.setBorderStyle(borderThick);
polygon.setContents("Polygon annotation");
annotations.add(polygon);
showPageNo(document, page1, "Page 1");
showPageNo(document, page2, "Page 2");
......
......@@ -57,6 +57,7 @@ import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampToken;
import org.bouncycastle.util.Selector;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.StoreException;
......@@ -266,10 +267,13 @@ public final class ShowSignature
// http://stackoverflow.com/a/9261365/535646
CMSProcessable signedContent = new CMSProcessableByteArray(byteArray);
CMSSignedData signedData = new CMSSignedData(signedContent, contents.getBytes());
@SuppressWarnings("unchecked")
Store<X509CertificateHolder> certificatesStore = signedData.getCertificates();
Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
Collection<X509CertificateHolder> matches = certificatesStore.getMatches(signerInformation.getSID());
@SuppressWarnings("unchecked")
Collection<X509CertificateHolder> matches =
certificatesStore.getMatches((Selector<X509CertificateHolder>) signerInformation.getSID());
X509CertificateHolder certificateHolder = matches.iterator().next();
X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder);
System.out.println("certFromSignedData: " + certFromSignedData);
......
......@@ -50,6 +50,7 @@ import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampToken;
import org.bouncycastle.util.Selector;
import org.bouncycastle.util.Store;
/**
......@@ -156,6 +157,7 @@ public class CertInformationCollector
try
{
CMSSignedData signedData = new CMSSignedData(signatureContent);
@SuppressWarnings("unchecked")
Store<X509CertificateHolder> certificatesStore = signedData.getCertificates();
SignerInformation signerInformation = processSignerStore(certificatesStore, signedData,
......@@ -239,8 +241,9 @@ public class CertInformationCollector
Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
@SuppressWarnings("unchecked")
Collection<X509CertificateHolder> matches = certificatesStore
.getMatches(signerInformation.getSID());
.getMatches((Selector<X509CertificateHolder>) signerInformation.getSID());
X509Certificate certificate = getCertFromHolder(matches.iterator().next());
......
......@@ -38,7 +38,7 @@ import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
public class CertInformationHelper
{
......@@ -146,7 +146,7 @@ public class CertInformationHelper
protected static void getAuthorityInfoExtensionValue(byte[] extensionValue,
CertSignatureInformation certInfo) throws IOException
{
ASN1Sequence asn1Seq = (ASN1Sequence) X509ExtensionUtil.fromExtensionValue(extensionValue);
ASN1Sequence asn1Seq = (ASN1Sequence) JcaX509ExtensionUtils.parseExtensionValue(extensionValue);
Enumeration<?> objects = asn1Seq.getObjects();
while (objects.hasMoreElements())
{
......@@ -171,8 +171,8 @@ public class CertInformationHelper
}
/**
* Gets the first CRL Url from given extension value. Structure has to be build as in 4.2.1.14
* CRL Distribution Points of RFC 2459.
* Gets the first CRL URL from given extension value. Structure has to be
* built as in 4.2.1.14 CRL Distribution Points of RFC 2459.
*
* @param extensionValue to get the extension value from
* @return first CRL- URL or null
......@@ -180,7 +180,7 @@ public class CertInformationHelper
*/
protected static String getCrlUrlFromExtensionValue(byte[] extensionValue) throws IOException
{
ASN1Sequence asn1Seq = (ASN1Sequence) X509ExtensionUtil.fromExtensionValue(extensionValue);
ASN1Sequence asn1Seq = (ASN1Sequence) JcaX509ExtensionUtils.parseExtensionValue(extensionValue);
Enumeration<?> objects = asn1Seq.getObjects();
while (objects.hasMoreElements())
......
......@@ -130,10 +130,21 @@ public final class RemoveAllText
if (token instanceof Operator)
{
Operator op = (Operator) token;
if ("TJ".equals(op.getName()) || "Tj".equals(op.getName()) ||
"'".equals(op.getName()) || "\"".equals(op.getName()))
if ("TJ".equals(op.getName()) ||
"Tj".equals(op.getName()) ||
"'".equals(op.getName()))
{
// remove the one argument to this operator
// remove the argument to this operator
newTokens.remove(newTokens.size() - 1);
token = parser.parseNextToken();
continue;
}
else if ("\"".equals(op.getName()))
{
// remove the 3 arguments to this operator
newTokens.remove(newTokens.size() - 1);
newTokens.remove(newTokens.size() - 1);
newTokens.remove(newTokens.size() - 1);
token = parser.parseNextToken();
......
......@@ -34,9 +34,9 @@ import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.examples.signature.CreateEmptySignatureForm;
import org.apache.pdfbox.examples.signature.CreateSignature;
......@@ -46,6 +46,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.util.Hex;
import org.apache.wink.client.MockHttpServer;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
......@@ -56,6 +57,7 @@ import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.tsp.TSPValidationException;
import org.bouncycastle.util.Selector;
import org.bouncycastle.util.Store;
import org.junit.Assert;
import org.junit.BeforeClass;
......@@ -123,7 +125,7 @@ public class TestCreateSignature
final String fileName = getOutputFileName("signed{0}.pdf");
signing.signDetached(new File(inDir + "sign_me.pdf"), new File(outDir + fileName));
checkSignature(new File(outDir + fileName));
checkSignature(new File(inDir, "sign_me.pdf"), new File(outDir, fileName));
}
/**
......@@ -209,7 +211,7 @@ public class TestCreateSignature
signing.signPDF(new File(inPath), destFile, null);
fis.close();
checkSignature(destFile);
checkSignature(new File(inPath), destFile);
}
/**
......@@ -251,7 +253,7 @@ public class TestCreateSignature
signing1.setExternalSigning(false);
signing1.signDetached(new File(filename), new File(filenameSigned1));
checkSignature(new File(filenameSigned1));
checkSignature(new File(filename), new File(filenameSigned1));
PDDocument doc1 = PDDocument.load(new File(filenameSigned1));
List<PDSignature> signatureDictionaries = doc1.getSignatureDictionaries();
......@@ -267,7 +269,7 @@ public class TestCreateSignature
signing2.signPDF(new File(filenameSigned1), new File(filenameSigned2), null, "Signature1");
fis.close();
checkSignature(new File(filenameSigned2));
checkSignature(new File(filenameSigned1), new File(filenameSigned2));
PDDocument doc2 = PDDocument.load(new File(filenameSigned2));
signatureDictionaries = doc2.getSignatureDictionaries();
......@@ -281,10 +283,18 @@ public class TestCreateSignature
}
// This check fails with a file created with the code before PDFBOX-3011 was solved.
private void checkSignature(File file)
private void checkSignature(File origFile, File signedFile)
throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
{
PDDocument document = PDDocument.load(file);
PDDocument document = PDDocument.load(origFile);
// get string representation of pages COSObject
String origPageKey = ((COSObject) document.getDocumentCatalog().getCOSObject().getItem(COSName.PAGES)).toString();
document.close();
document = PDDocument.load(signedFile);
// PDFBOX-4261: check that object number stays the same
Assert.assertEquals(origPageKey, document.getDocumentCatalog().getCOSObject().getItem(COSName.PAGES).toString());
List<PDSignature> signatureDictionaries = document.getSignatureDictionaries();
if (signatureDictionaries.isEmpty())
{
......@@ -294,7 +304,7 @@ public class TestCreateSignature
{
COSString contents = (COSString) sig.getCOSObject().getDictionaryObject(COSName.CONTENTS);
FileInputStream fis = new FileInputStream(file);
FileInputStream fis = new FileInputStream(signedFile);
byte[] buf = sig.getSignedContent(fis);
fis.close();
......@@ -305,7 +315,7 @@ public class TestCreateSignature
Store certificatesStore = signedData.getCertificates();
Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
Collection matches = certificatesStore.getMatches(signerInformation.getSID());
Collection matches = certificatesStore.getMatches((Selector<X509CertificateHolder>) signerInformation.getSID());
X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder);
......@@ -324,7 +334,7 @@ public class TestCreateSignature
private String calculateDigestString(InputStream inputStream) throws NoSuchAlgorithmException, IOException
{
MessageDigest md = MessageDigest.getInstance("SHA-256");
return DatatypeConverter.printHexBinary(md.digest(IOUtils.toByteArray(inputStream)));
return Hex.getString(md.digest(IOUtils.toByteArray(inputStream)));
}
/**
......