Author: tilman
Date: Sat Dec 1 05:36:02 2018
New Revision: 1847875
URL: http://svn.apache.org/viewvc?rev=1847875&view=rev
Log:
PDFBOX-3017: retrieve additional certificates from id-ad-caIssuers in the
authority information access extension
Modified:
pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/cert/CertificateVerifier.java
Modified:
pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/cert/CertificateVerifier.java
URL:
http://svn.apache.org/viewvc/pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/cert/CertificateVerifier.java?rev=1847875&r1=1847874&r2=1847875&view=diff
==============================================================================
---
pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/cert/CertificateVerifier.java
(original)
+++
pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/cert/CertificateVerifier.java
Sat Dec 1 05:36:02 2018
@@ -20,6 +20,8 @@
package org.apache.pdfbox.examples.signature.cert;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.PublicKey;
@@ -27,7 +29,9 @@ import java.security.SignatureException;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertStore;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
@@ -35,12 +39,14 @@ import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Calendar;
+import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.encryption.SecurityProvider;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
@@ -56,6 +62,8 @@ import org.bouncycastle.cert.jcajce.JcaX
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPResp;
+import org.bouncycastle.util.CollectionStore;
+import org.bouncycastle.util.Store;
/**
* Copied from Apache CXF 2.4.9, initial version:
@@ -242,6 +250,84 @@ public final class CertificateVerifier
}
/**
+ * Download extra certificates from the URI mentioned in id-ad-caIssuers
in the "authority
+ * information access" extension of the certificate. These are added to
the store and the
+ * possibly updated store is returned. The method is lenient, i.e. catches
all exceptions.
+ *
+ * @param certFromSignedData
+ * @param certificatesStore
+ * @return the updated certificates store.
+ */
+ public static Store<X509CertificateHolder> addExtraCertificatesToStore(
+ X509Certificate certFromSignedData, Store<X509CertificateHolder>
certificatesStore)
+ {
+ // https://tools.ietf.org/html/rfc2459#section-4.2.2.1
+ // https://tools.ietf.org/html/rfc3280#section-4.2.2.1
+ // https://tools.ietf.org/html/rfc4325
+ byte[] authorityExtensionValue =
certFromSignedData.getExtensionValue(Extension.authorityInfoAccess.getId());
+ if (authorityExtensionValue != null)
+ {
+ ASN1Sequence asn1Seq;
+ try
+ {
+ asn1Seq = (ASN1Sequence)
JcaX509ExtensionUtils.parseExtensionValue(authorityExtensionValue);
+ }
+ catch (IOException ex)
+ {
+ LOG.warn(ex.getMessage(), ex);
+ return certificatesStore;
+ }
+ Enumeration<?> objects = asn1Seq.getObjects();
+ while (objects.hasMoreElements())
+ {
+ // AccessDescription
+ ASN1Sequence obj = (ASN1Sequence) objects.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)
obj.getObjectAt(0);
+ if (oid.equals(X509ObjectIdentifiers.id_ad_caIssuers))
+ {
+ DERTaggedObject location = (DERTaggedObject)
obj.getObjectAt(1);
+ DEROctetString uri = (DEROctetString) location.getObject();
+ InputStream in = null;
+ try
+ {
+ URL certUrl = new URL(new String(uri.getOctets()));
+ LOG.info("CA issuers URL: " + certUrl);
+ CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
+
+ in = certUrl.openStream();
+ // use Set to get rid of duplicates
+ Set<X509CertificateHolder> certSet =
+ new
HashSet<X509CertificateHolder>(certificatesStore.getMatches(null));
+ int oldCertSetSize = certSet.size();
+ Collection<? extends Certificate> altCerts =
certFactory.generateCertificates(in);
+ LOG.info("CA issuers URL: " + altCerts.size() + "
certificate(s) loaded");
+ // Create new store that contains the online
certificates
+ for (Certificate altCert : altCerts)
+ {
+ certSet.add(new
X509CertificateHolder(altCert.getEncoded()));
+ }
+ certificatesStore = new
CollectionStore<X509CertificateHolder>(certSet);
+ LOG.info("CA issuers URL: " + (certSet.size() -
oldCertSetSize) + " new certificate(s)");
+ }
+ catch (IOException ex)
+ {
+ LOG.warn(ex.getMessage(), ex);
+ }
+ catch (CertificateException ex)
+ {
+ LOG.warn(ex.getMessage(), ex);
+ }
+ finally
+ {
+ IOUtils.closeQuietly(in);
+ }
+ }
+ }
+ }
+ return certificatesStore;
+ }
+
+ /**
* Attempts to build a certification chain for given certificate and to
* verify it. Relies on a set of root CA certificates (trust anchors) and a
* set of intermediate certificates (to be used as part of the chain).